From 9447f59d59496de499a1a8d128004a7ed3743e60 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 14 Jul 2023 00:26:36 +0200 Subject: [PATCH 1/3] drivers/st77xx: fix initialization sequences fror ST77xx --- drivers/include/st77xx.h | 267 +++++++++++++++++++++++ drivers/lcd/include/lcd_internal.h | 3 + drivers/st77xx/Makefile | 14 ++ drivers/st77xx/include/st7735_internal.h | 54 +++++ drivers/st77xx/include/st7789_internal.h | 61 ++++++ drivers/st77xx/include/st7796_internal.h | 51 +++++ drivers/st77xx/include/st77xx_internal.h | 4 +- drivers/st77xx/st7735_init.c | 261 ++++++++++++++++++++++ drivers/st77xx/st7789_init.c | 245 +++++++++++++++++++++ drivers/st77xx/st7796_init.c | 204 +++++++++++++++++ drivers/st77xx/st77xx.c | 91 ++++---- 11 files changed, 1202 insertions(+), 53 deletions(-) create mode 100644 drivers/st77xx/include/st7735_internal.h create mode 100644 drivers/st77xx/include/st7789_internal.h create mode 100644 drivers/st77xx/include/st7796_internal.h create mode 100644 drivers/st77xx/st7735_init.c create mode 100644 drivers/st77xx/st7789_init.c create mode 100644 drivers/st77xx/st7796_init.c diff --git a/drivers/include/st77xx.h b/drivers/include/st77xx.h index 8e1825a05157..f88b711a0a73 100644 --- a/drivers/include/st77xx.h +++ b/drivers/include/st77xx.h @@ -53,6 +53,273 @@ extern "C" { #endif +/** + * @brief ST7735 Customized Configuration Enable + * + * Define CONFIG_ST7735_CUSTOM_CONFIG=1 to use customized voltage + * configurations. Otherwise ST7735 is using reset defaults. + */ +#ifndef CONFIG_ST7735_CUSTOM_CONFIG +#define CONFIG_ST7735_CUSTOM_CONFIG 0 +#endif + +/** + * @brief ST7735 AVDD voltage (in millivolts) + * + * A default voltage of 4.9V is used for AVDD. + * Valid values must be in the range of 4500 (4.5V) to 5100 (5.1V) + * in steps of 100. + */ +#ifndef CONFIG_ST7735_AVDD +#define CONFIG_ST7735_AVDD 4900 +#endif + +/** + * @brief ST7735 GVDD voltage (in millivolts) + * + * A default voltage of 4.6V is used for GVDD (gamma reference positive voltage). + * Valid values must be in the range of 3150 (3.15V) to 4700 (4.7V) + * in steps of 50. + */ +#ifndef CONFIG_ST7735_GVDD +#define CONFIG_ST7735_GVDD 4600 +#endif + +/** + * @brief ST7735 GVL voltage (in millivolts) + * + * A default voltage of -4.6V is used for GVCL (gamma reference negative voltage). + * Valid values must be in the range of -4700 (-4.7V) to -3150 (-3.15V) + * in steps of 50. + */ +#ifndef CONFIG_ST7735_GVCL +#define CONFIG_ST7735_GVCL -4600 +#endif + +/** + * @brief ST7735 VCOM voltage (in millivolts) + * + * A default voltage of -0.425V is used for VCOM. VCOM needs to be adjusted + * to match the capacitance and performance specifications of the TFT panel + * to maximize contrast and minimize flickering. + * Valid values must be in the range of -2000 (-2.0V) to -425 (-0.425V) + * in steps of 25. + */ +#ifndef CONFIG_ST7735_VCOM +#define CONFIG_ST7735_VCOM -775 +#endif + +/** + * @brief ST7735 VGH voltage (in millivolts) + * + * A default voltage of 14.7V is used for VGH, the high voltage for gate drivers. + * Valid values must be in the range of 10000 (10V) to 15000 (15V) and + * in the range of (2 * AVDD + 2.1V) and (3 * AVDD + 2.4 V). + */ +#ifndef CONFIG_ST7735_VGH +#define CONFIG_ST7735_VGH 14700 +#endif + +/** + * @brief ST7735 VGL voltage (in millivolts) + * + * A default voltage of -10V is used for VGL, the low voltage for gate drivers. + * Valid values must be in the range of -13000 (-13V) to -7500 (-7.5V) + * in steps of 2500. + */ +#ifndef CONFIG_ST7735_VGL +#define CONFIG_ST7735_VGL -10000 +#endif + +/** + * @brief ST7789 Customized Configuration Enable + * + * Define CONFIG_ST7789_CUSTOM_CONFIG=1 to use customized voltage + * configurations. Otherwise ST7735 is using reset defaults. + */ +#ifndef CONFIG_ST7789_CUSTOM_CONFIG +#define CONFIG_ST7789_CUSTOM_CONFIG 0 +#endif + +/** + * @brief ST7789 AVDD voltage (in millivolts) + * + * A default voltage of 6.8V is used for AVDD. + * Valid values must be in the range of 6400 (6.4V) to 6800 (6.8V) + * in steps of 100. + */ +#ifndef CONFIG_ST7789_AVDD +#define CONFIG_ST7789_AVDD 6800 +#endif + +/** + * @brief ST7789 AVCL voltage (in millivolts) + * + * A default voltage of -4.8V is used for AVCL. + * Valid values must be in the range of -5000 (-5.0V) to -4400 (-4.4V) + * in steps of 100. + */ +#ifndef CONFIG_ST7789_AVCL +#define CONFIG_ST7789_AVCL -4800 +#endif + +/** + * @brief ST7789 VCOM voltage (in millivolts) + * + * A default voltage of 0.9V is used for VCOM. VCOM needs to be adjusted + * to match the capacitance and performance specifications of the TFT panel + * to maximize contrast and minimize flickering. VCOM is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + * GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + * + * Valid values must be in the range of 100 (0.1V) to 1675 (1.675V) + * in steps of 25. + */ +#ifndef CONFIG_ST7789_VCOM +#define CONFIG_ST7789_VCOM 900 +#endif + +/** + * @brief ST7789 VCOM voltage offset (in millivolts) + * + * A default voltage of 0V is used for VCOM voltage offset (VCOM_OFFSET). + * VCOM_OFFSET is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + * GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + * + * Valid values must be in the range of -800 (-0.8V) to 775 (0.775V) + * in steps of 25. + */ +#ifndef CONFIG_ST7789_VCOM_OFFSET +#define CONFIG_ST7789_VCOM_OFFSET 0 +#endif + +/** + * @brief ST7789 VDV voltage (in millivolts) + * + * A default voltage of 0V is used for VDV. VDV is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + * GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + * + * Valid values must be in the range of -800 (-0.8V) to 775 (0.775V) + * in steps of 25. + */ +#ifndef CONFIG_ST7789_VDV +#define CONFIG_ST7789_VDV 0 +#endif + +/** + * @brief ST7789 VRH voltage (in millivolts) + * + * A default voltage of 4.1V is used for VRH. VRH is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + * GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + * + * Valid values must be in the range of 3350 (3.35V) to 5500 (5.5V) + * in steps of 50. + */ +#ifndef CONFIG_ST7789_VRH +#define CONFIG_ST7789_VRH 4100 +#endif + +/** + * @brief ST7796 Customized Configuration Enable + * + * Define CONFIG_ST7796_CUSTOM_CONFIG=1 to use customized voltage + * configurations. Otherwise ST7735 is using reset defaults. + */ +#ifndef CONFIG_ST7796_CUSTOM_CONFIG +#define CONFIG_ST7796_CUSTOM_CONFIG 0 +#endif + +/** + * @brief ST7796 AVDD voltage (in millivolts) + * + * A default voltage of 6.6V is used for AVDD. + * Valid values must be in the range of 6200 (6.2V) to 6800 (6.8V) + * in steps of 100. + */ +#ifndef CONFIG_ST7796_AVDD +#define CONFIG_ST7796_AVDD 6600 +#endif + +/** + * @brief ST7796 AVCL voltage (in millivolts) + * + * A default voltage of -4.4V is used for AVCL. + * Valid values must be in the range of -5000 (-5.0V) to -4400 (-4.4V) + * in steps of 100. + */ +#ifndef CONFIG_ST7796_AVCL +#define CONFIG_ST7796_AVCL -4400 +#endif + +/** + * @brief ST7796 VCOM voltage (in millivolts) + * + * A default voltage of 1.0V is used for VCOM. VCOM needs to be adjusted + * to match the capacitance and performance specifications of the TFT panel + * to maximize contrast and minimize flickering. VCOM is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + * GVCL = -VRH + VCOM + VCOM_OFFSET + * + * Valid values must be in the range of 100 (0.1V) to 1875 (1.875V) + * in steps of 25. + */ +#ifndef CONFIG_ST7796_VCOM +#define CONFIG_ST7796_VCOM 1000 +#endif + +/** + * @brief ST7796 VCOM voltage offset (in millivolts) + * + * A default voltage of 0V is used for VCOM voltage offset (VCOM_OFFSET). + * VCOM_OFFSET is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + * GVCL = -VRH + VCOM + VCOM_OFFSET + * + * Valid values must be in the range of -800 (-0.8V) to 775 (0.775V) + * in steps of 25. + */ +#ifndef CONFIG_ST7796_VCOM_OFFSET +#define CONFIG_ST7796_VCOM_OFFSET 0 +#endif + +/** + * @brief ST7796 VRH voltage (in millivolts) + * + * A default voltage of 4.1V is used for VRH. VRH is used to derive + * the GVDD (gamma reference positive voltage) and + * the GVCL (gamma reference negative voltage) as follows: + * + * GDDV = +VRH + VCOM + VCOM_OFFSET + * GVCL = -VRH + VCOM + VCOM_OFFSET + * + * Valid values must be in the range of 3350 (3.35V) to 5500 (5.5V) + * in steps of 50. + */ +#ifndef CONFIG_ST7796_VRH +#define CONFIG_ST7796_VRH 4100 +#endif + /** * @name ST77xx display rotation modes * @{ diff --git a/drivers/lcd/include/lcd_internal.h b/drivers/lcd/include/lcd_internal.h index 3754dc077dfa..9e906ddc8040 100644 --- a/drivers/lcd/include/lcd_internal.h +++ b/drivers/lcd/include/lcd_internal.h @@ -51,6 +51,9 @@ extern "C" { #define LCD_CMD_MADCTL 0x36 /**< Memory data access control */ #define LCD_CMD_IDMOFF 0x38 /**< Idle Mode OFF */ #define LCD_CMD_IDMON 0x39 /**< Idle Mode ON */ +#define LCD_CMD_TEOFF 0x34 /**< Tearing Effect Line Off */ +#define LCD_CMD_TEON 0x35 /**< Tearing Effect Line On */ +#define LCD_CMD_COLMOD 0x3A /**< Interface Pixel Format Set */ #define LCD_CMD_PIXSET 0x3A /**< COLMOD: Pixel Format Set */ #define LCD_CMD_WRDISBV 0x51 /**< Write Display Brightness */ #define LCD_CMD_WRCTRLD 0x53 /**< Write Control Display */ diff --git a/drivers/st77xx/Makefile b/drivers/st77xx/Makefile index 48422e909a47..59ed58f5e7f2 100644 --- a/drivers/st77xx/Makefile +++ b/drivers/st77xx/Makefile @@ -1 +1,15 @@ +SRC = st77xx.c + +ifneq (,$(filter st7735,$(USEMODULE))) + SRC += st7735_init.c +endif + +ifneq (,$(filter st7789,$(USEMODULE))) + SRC += st7789_init.c +endif + +ifneq (,$(filter st7796,$(USEMODULE))) + SRC += st7796_init.c +endif + include $(RIOTBASE)/Makefile.base diff --git a/drivers/st77xx/include/st7735_internal.h b/drivers/st77xx/include/st7735_internal.h new file mode 100644 index 000000000000..d1ae09a58079 --- /dev/null +++ b/drivers/st77xx/include/st7735_internal.h @@ -0,0 +1,54 @@ +/* + * 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 + * directory for more details. + */ + +/** + * @ingroup drivers_st77xx + * @{ + * + * @file + * @brief Specific internal definitions for the ST7735 controller variant + * + * @author Koen Zandberg + * @author Gunar Schorcht + * + * @} + */ + +#ifndef ST7735_INTERNAL_H +#define ST7735_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "st77xx_internal.h" + +/** + * @name LCD ST7735 commands + * + * LCD commands extension available for ST7735 LCD controllers + * @{ + */ +#define LCD_CMD_INVCTR 0xb4 /**< Display Inversion Control */ +#define LCD_CMD_PWCTRL3 0xc2 /**< Power control 3 */ +#define LCD_CMD_PWCTRL4 0xc3 /**< Power control 4 */ +#define LCD_CMD_PWCTRL5 0xc4 /**< Power control 5 */ +#define LCD_CMD_PWCTRL6 0xfc /**< Power control 6 */ +/** @} */ + +/** + * @brief ST7735 controller specific initialization part + */ +int st7735_init(lcd_t *dev, const lcd_params_t *params); + +#ifdef __cplusplus +} +#endif + +#endif /* ST7735_INTERNAL_H */ diff --git a/drivers/st77xx/include/st7789_internal.h b/drivers/st77xx/include/st7789_internal.h new file mode 100644 index 000000000000..3e249d8aea30 --- /dev/null +++ b/drivers/st77xx/include/st7789_internal.h @@ -0,0 +1,61 @@ +/* + * 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 + * directory for more details. + */ + +/** + * @ingroup drivers_st77xx + * @{ + * + * @file + * @brief Specific internal definitions for the ST7789 controller variant + * + * @author Koen Zandberg + * @author Gunar Schorcht + * + * @} + */ + +#ifndef ST7789_INTERNAL_H +#define ST7789_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "st77xx_internal.h" + +/** + * @name LCD ST7789 commands + * + * LCD commands extension available for ST7789 LCD controllers + * @{ + */ +#define LCD_CMD_RAMWRC 0x3c /**< Memory Write Continue */ +#define LCD_CMD_RAMRDC 0x3e /**< Memory Read Continue */ +#define LCD_CMD_PORCTRL 0xb2 /**< Porch Control */ +#define LCD_CMD_GCTRL 0xb7 /**< Gate Control */ +#define LCD_CMD_VCOMS 0xbb /**< VCOM Setting */ +#define LCD_CMD_LCMCTRL 0xc0 /**< LCM Control */ +#define LCD_CMD_VDVVRHEN 0xc2 /**< VDV and VRH Command Enable */ +#define LCD_CMD_VRHS 0xc3 /**< VRH Set */ +#define LCD_CMD_VDVS 0xc4 /**< VDV Set */ +#define LCD_CMD_VCMOFSET 0xc4 /**< VCOM Offset Set */ +#define LCD_CMD_FRCTRL2 0xc6 /**< Frame Rate Control in Normal Mode */ +#define LCD_CMD_PWCTRL1X 0xd0 /**< Power Control 1 */ +/** @} */ + +/** + * @brief ST7789 controller specific initialization part + */ +int st7789_init(lcd_t *dev, const lcd_params_t *params); + +#ifdef __cplusplus +} +#endif + +#endif /* ST7789_INTERNAL_H */ diff --git a/drivers/st77xx/include/st7796_internal.h b/drivers/st77xx/include/st7796_internal.h new file mode 100644 index 000000000000..b173420b17a7 --- /dev/null +++ b/drivers/st77xx/include/st7796_internal.h @@ -0,0 +1,51 @@ +/* + * 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 + * directory for more details. + */ + +/** + * @ingroup drivers_st77xx + * @{ + * + * @file + * @brief Specific internal definitions for the ST7789 controller variant + * + * @author Koen Zandberg + * @author Gunar Schorcht + * + * @} + */ + +#ifndef ST7796_INTERNAL_H +#define ST7796_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "st77xx_internal.h" + +/** + * @name LCD ST7796 commands + * + * LCD commands extension available for ST7796 LCD controllers + * @{ + */ +#define LCD_CMD_VCMPCTL 0xc5 /**< VCOM Control */ +#define LCD_CMD_VCM 0xc6 /**< VCOM Offset */ +/** @} */ + +/** + * @brief ST7796 controller specific initialization part + */ +int st7796_init(lcd_t *dev, const lcd_params_t *params); + +#ifdef __cplusplus +} +#endif + +#endif /* ST7796_INTERNAL_H */ diff --git a/drivers/st77xx/include/st77xx_internal.h b/drivers/st77xx/include/st77xx_internal.h index a516f03d9e03..35759642722d 100644 --- a/drivers/st77xx/include/st77xx_internal.h +++ b/drivers/st77xx/include/st77xx_internal.h @@ -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 @@ -11,9 +12,10 @@ * @{ * * @file - * @brief Device driver implementation for the ST77xx display controller + * @brief Internal definitions that are common for all ST77xx controllers * * @author Koen Zandberg + * @author Gunar Schorcht * * @} */ diff --git a/drivers/st77xx/st7735_init.c b/drivers/st77xx/st7735_init.c new file mode 100644 index 000000000000..273e3fe9b04c --- /dev/null +++ b/drivers/st77xx/st7735_init.c @@ -0,0 +1,261 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @ingroup drivers_st77xx + * @{ + * + * @file + * @brief Controller specific initialization for ST7735 + * + * @author Gunar Schorcht + * + * This file is only compiled if the `st7735` module is enabled. + * + * @} + */ + +#include +#include + +#include "byteorder.h" +#include "kernel_defines.h" +#include "ztimer.h" + +#include "st77xx.h" +#include "st7735_internal.h" +#include "lcd.h" +#include "lcd_internal.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if CONFIG_ST7735_CUSTOM_CONFIG +/* avdd in mV with in 100 mV steps: 4600 = 4.6V + * Datasheet page 130: + * + * y = 0 for avdd < 4500 (< 4.5V) + * y = (5100 - avdd) / 100 for avdd = 4500 to 5100 (4.5V to 5.1V) + * y = 6 for avdd > 5100 (> 5.1V) + * + * default value after reset is 4.9 V (0x04) + */ +static inline uint8_t _st7735_calc_avdd(uint16_t avdd) +{ + assert((avdd >= 4500) && (avdd <= 5100)); + assert((avdd % 100) == 0); + + return (5100 - avdd) / 100; +} + +/* gvdd in mV with 50 mV increments: 4650 = 4.65V + * Datasheet page 130: + * + * y = 31 for gddv < 3150 (< 3.15V) + * y = 31 - ((gddv - 3150) / 50) for gddv = 3150 to 4700 (3.15V to 4.7V) + * y = 0 for gddv > 4700 (> 4.7V) + * + * default value after reset is 4.6 V (0x02) + */ +static inline uint8_t _st7735_calc_gvdd(uint16_t gvdd) +{ + assert((gvdd >= 3150) && (gvdd <= 4700)); + assert((gvdd % 50) == 0); + + return 31 - ((gvdd - 3150) / 50); +} + +/* gvcl in mV with 50 mV increments: -4650 = -4.65V + * Datasheet page 130: + * + * y = 0 for gdcl < -4700 (< -4.7V) + * y = 31 - (-3150 - gvcl) / 50) for gddv = -4700 to -3150 (-4.7V to -3.15V) + * y = 31 for gddv > -3150 (> -3.15V) + * + * default value after reset is -4.6 V (0x02) + */ +static inline uint8_t _st7735_calc_gvcl(int16_t gvcl) +{ + assert((gvcl >= -4700) && (gvcl <= -3150)); + assert((gvcl % 50) == 0); + + return 31 - ((-3150 - gvcl) / 50); +} + +/* vcom in mV with 25 mV increments: -625 = -0.625V + * Datasheet page 140: + * + * y = 63 for vcom < -2000 (> 2V) + * y = 63 - ((2000 + vcom) / 25) for vcom = -2000 to -425 (-2V to -0.425V) + * y = 0 for vcom > -425 (< -0.425V) + * + * default value after reset is 4.9 V (4) + */ +static inline uint8_t _st7735_calc_vcom(int16_t vcom) +{ + assert((vcom >= -2000) && (vcom <= 425)); + assert((vcom % 25) == 0); + + return 63 - ((2000 + vcom) / 25); +} + +/* vgh in mV with 100 mV increments: 11200 = 11.2V + * vgl in mV with 2500 mV increments: 12500 = 12.5V + * Datasheet page 132 + */ +static inline uint8_t _st7735_calc_vghl(uint16_t vgh, int16_t vgl, uint16_t avdd) +{ + assert((vgh >= 10000) && (vgh <= 15000)); + assert((vgl >= -13000) && (vgl <= 7500)); + assert((vgh >= ((avdd * 2) + 2100)) && (vgh <= ((3 * avdd) + 2400))); + + uint16_t bt = vgh / avdd; + uint16_t h25 = 0; + assert((bt == 2) || (bt == 3)); /* bt must be either 2 or 3 */ + + if ((vgh - (bt * avdd)) > 2100) { + /* if there remains an offset of at least 2.1V, use VGH25 */ + h25 = ((vgh - (bt * avdd)) - 2100) / 100; + assert(h25 <= 3); + } + + bt -= 2; /* convert (3 * AVDD) to 01b and (2 * AVDD) to 00b */ + + if (bt && h25) { + /* represents 3 * AVDD + VGH25 */ + bt++; + } + else { + h25 = 3; + } + + uint16_t sel = (vgl < -12500) ? 3 : 2 - ((vgl + 12500) / 2500); + + return (h25 << 6) + (sel << 2) + bt; +} +#endif /* CONFIG_ST7735_CUSTOM_CONFIG */ + +int st7735_init(lcd_t *dev, const lcd_params_t *params) +{ + assert(params->lines <= 162); + assert(params->rgb_channels <= 132); + + uint8_t command_params[6] = { 0 }; + + /* INVCTR (B4h): Display Inversion Control */ + command_params[0] = 0x07; /* NLA=1, NLB=1, NLC=1 Line inversion in all modes */ + lcd_ll_write_cmd(dev, LCD_CMD_INVCTR, command_params, 1); + +#if CONFIG_ST7735_CUSTOM_CONFIG + + /* PWCTR1 (C0h): Power Control 1 */ + command_params[0] = (_st7735_calc_avdd(CONFIG_ST7735_AVDD) << 5) | + _st7735_calc_gvdd(CONFIG_ST7735_GVDD); + com mand_params[1] = _st7735_calc_gvcl(CONFIG_ST7735_GVCL); + command_params[2] = 0x84; /* AUTO mode */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 3); + DEBUG("PWCTRL1 (C0h): %02x %02x %02x\n", + command_params[0], command_params[1], command_params[2]); + + /* PWCTR2 (C1h): Power Control 2 (== reset defaults) */ + command_params[0] = _st7735_calc_vghl(CONFIG_ST7735_VGH, CONFIG_ST7735_VGL, + CONFIG_ST7735_AVDD); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 1); + DEBUG("PWCTRL2 (C1h): %02x\n", command_params[0]); + + /* VMCTR1 (C5h): VCOM Control 1 */ + command_params[0] = _st7735_calc_vcom(CONFIG_ST7735_VCOM); + lcd_ll_write_cmd(dev, LCD_CMD_VMCTRL1, command_params, 1); + DEBUG("VMCTR1 (C5h): %02x\n", command_params[0]); + +#else /* CONFIG_ST7735_CUSTOM_CONFIG */ + +#if 0 /* no need to write reset defaults, just for documentation purpose */ + + /* PWCTR1 (C0h): Power Control 1 (== reset defaults) */ + command_params[0] = 0x82; /* AVDD=4.9V, GVDD=4.6V */ + command_params[1] = 0x02; /* GVCL=-4.6V */ + command_params[2] = 0x84; /* AUTO mode */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 3); + + /* PWCTR2 (C1h): Power Control 2 (== reset defaults) */ + command_params[0] = 0xc5; /* VGH=3*AVDD, VGL=-10V */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 1); + + /* VMCTR1 (C5h): VCOM Control 1 (== reset defaults) */ + command_params[0] = 0x04; /* VCOM=-0.525V */ + lcd_ll_write_cmd(dev, LCD_CMD_VMCTRL1, command_params, 1); + +#endif /* no need to write reset defaults, just for documentation purpose */ + +#endif /* CONFIG_ST7735_CUSTOM_CONFIG */ + +#if 0 /* no need to write reset defaults, just for documentation purpose */ + + /* PWCTR3 (C2h): Power Control 3 Normal Mode (== reset defaults) */ + command_params[0] = 0x0a; /* AP=Medium Low, SAP=Small */ + command_params[0] = 0x00; /* DCA=BCLK/1 BCLK/1 BCLK/1 BCLK/1 BCLK/1 */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL3, command_params, 2); + + /* PWCTR4 (C3h): Power Control 4 Idle Mode (== reset defaults) */ + command_params[0] = 0x8a; /* AP=Medium Low, SAP=Small */ + command_params[1] = 0x2e; /* DCA=BCLK/2 BCLK/1 BCLK/2 BCLK/4 BCLK/2 */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL4, command_params, 2); + + /* PWCTR5 (C4h): Power Control 5 Partial Mode (== reset defaults) */ + command_params[0] = 0x8a; /* AP=Medium Low, SAP=Small */ + command_params[1] = 0xaa; /* DCA=BCLK/2 BCLK/2 BCLK/2 BCLK/2 BCLK/2 */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL5, command_params, 2); + + /* FRMCTRL1 (B1H): Frame Control 1 in Normal mode (== reset defaults) */ + /* Frame rate = fosc/((RNTA * 2 + 40) x (lines + FPA + BPA)) with fosc = 624 kHz */ + command_params[0] = 0x01; /* RNTA=1 */ + command_params[1] = 0x2c; /* FPA (Front Porch) = 44 lines */ + command_params[2] = 0x2d; /* BPA (Back Porch) = 45 lines */ + lcd_ll_write_cmd(dev, LCD_CMD_FRAMECTL1, command_params, 3); + + /* FRMCTRL2 (B2H): Frame Control 2 in Idle mode (== reset defaults) */ + /* Frame rate = fosc/((RNTB * 2 + 40) x (lines + FPB + BPB)) with fosc = 624 kHz */ + command_params[0] = 0x01; /* RNTB=1 */ + command_params[1] = 0x2c; /* FPB (Front Porch) = 44 lines */ + command_params[2] = 0x2d; /* BPB (Back Porch) = 45 lines */ + lcd_ll_write_cmd(dev, LCD_CMD_FRAMECTL2, command_params, 3); + + /* FRMCTRL3 (B3H): Frame Control 3 in Partal mode (== reset defaults) */ + /* Frame rate = fosc/((RNTC * 2 + 40) x (lines + FPC + BPC)) with fosc = 624 kHz */ + command_params[0] = 0x01; /* RNTC=1 */ + command_params[1] = 0x2c; /* FPC (Front Porch) = 44 lines */ + command_params[2] = 0x2d; /* BPC (Back Porch) = 45 lines */ + command_params[3] = 0x01; /* RNTD=1 */ + command_params[4] = 0x2c; /* FPD (Front Porch) = 44 lines */ + command_params[5] = 0x2d; /* BPD (Back Porch) = 45 lines */ + lcd_ll_write_cmd(dev, LCD_CMD_FRAMECTL3, command_params, 6); + +#endif /* no need to write reset defaults, just for documentation purpose */ + + /* GMCTRP1 (E0h): Gamma +polarity Correction Characteristics Setting */ + { + static const uint8_t gamma_pos[] = { + 0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, + 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10 + }; + lcd_ll_write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, + sizeof(gamma_pos)); + } + /* GMCTRN1 (E1h): Gamma -polarity Correction Characteristics Setting */ + { + static const uint8_t gamma_neg[] = { + 0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, + 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10 + }; + lcd_ll_write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, + sizeof(gamma_neg)); + } + + return 0; +} diff --git a/drivers/st77xx/st7789_init.c b/drivers/st77xx/st7789_init.c new file mode 100644 index 000000000000..b1ab9da9c0b3 --- /dev/null +++ b/drivers/st77xx/st7789_init.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @ingroup drivers_st77xx + * @{ + * + * @file + * @brief Controller specific initialization for ST7789 + * + * @author Gunar Schorcht + * + * This file is only compiled if the `st7789` module is enabled. + * + * @} + */ + +#include +#include + +#include "byteorder.h" +#include "kernel_defines.h" +#include "ztimer.h" + +#include "st77xx.h" +#include "st7789_internal.h" +#include "lcd.h" +#include "lcd_internal.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if CONFIG_ST7789_CUSTOM_CONFIG +/* avdd in mV with 200 mV increments: 6600 = 6.6V + * Datasheet page 289: + * + * y = 0 for avdd < 6400 (< 6.4V) + * y = (avdd - 6400) / 200 for avdd = 6400 to 6800 (6.4 to 6.8V) + * y = 2 for avdd > 6800 (> 6.8V) + * + * default value after reset is 6.8 V (0x02) + */ +static inline uint8_t _st7789_calc_avdd(int16_t avdd) +{ + assert((avdd >= 6400) && (avdd <= 6800)); + assert((avdd % 200) == 0); + + return (avdd - 6400) / 200; +} + +/* avcl in mV with 200 mV increments: -4800 = -4.8V + * Datasheet page 289: + * + * y = 0 for avcl < -5000 (< -5.0V) + * y = 3 - ((avcl + 5000) / 200) for avcl = -5000 to -4400 (-5.0V to -4.4V) + * y = 3 for avcl > -4400 (> -4.4V) + * + * default value after reset is -4.8 V (0x02) + */ +static inline uint8_t _st7789_calc_avcl(int16_t avcl) +{ + assert((avcl >= -5000) && (avcl <= -4400)); + assert((avcl % 200) == 0); + + return 3 - ((avcl + 5000) / 200); +} + +/* vcom in mV with 25 mV increments: 1325 = 1.325V + * Datasheet page 270: + * + * y = 0 for vcom < 100 (< 0.1V) + * y = (vcom - 100) / 25 for vcom = 100 to 1675 (0.1V to 1.675V) + * y = 63 for vcom > 1675 (> 1.675V) + * + * default value after reset is 0.9 V (0x20) + */ +static inline uint8_t _st7789_calc_vcom(int16_t vcom) +{ + assert((vcom >= 100) && (vcom <= 1675)); + assert((vcom % 25) == 0); + + return (vcom - 100) / 25; +} + +/* vol in mV with 25 mV increments: 100 = 0.1V + * Datasheet page 279: + * + * y = 0 for vol < -800 (< -0.8V) + * y = (vol + 800) / 25 for vol = -800 to 775 (-0.8V to 0.775V) + * y = 63 for vol > 0.775 (> 0.775V) + * + * default value after reset is 0 V (0x00) + */ +static inline uint8_t _st7789_calc_vcom_offset_vdv(int16_t vol) +{ + assert((vol >= -800) && (vol <= 775)); + assert((vol % 25) == 0); + + return (vol + 800) / 25; +} + +/* vrh in mV with 50 mV increments: 4800 = 4.8V + * Datasheet page 277: + * + * y = 0 for vrh < 3550 (< 3.55V) + * y = (vrh - 3550) / 50 for vrh = 3550 to 5500 (3.55V to 5.5V) + * y = 39 for vrh > 5500 (> -4.4V) + * + * default value after reset is 4.1 V (0x0b) + */ +static inline uint8_t _st7789_calc_vrh(int16_t vrh) +{ + assert((vrh >= 3550) && (vrh <= 5500)); + assert((vrh % 50) == 0); + + return (vrh - 3550) / 50; +} +#endif /* CONFIG_ST7789_CUSTOM_CONFIG */ + +int st7789_init(lcd_t *dev, const lcd_params_t *params) +{ + assert(params->lines <= 320); + assert(params->rgb_channels <= 240); + + uint8_t command_params[5] = { 0 }; + (void)command_params; + +#if 0 /* no need to write reset defaults, just for documentation purpose */ + + /* LCMCTRL (C0h): LCM Control (== reset defaults) */ + command_params[0] = 0x2c; /* XOR RGB, MX and MH setting in command 36h */ + lcd_ll_write_cmd(dev, LCD_CMD_LCMCTRL, command_params, 1); + DEBUG("LCMCTRL (C0h) %02x\n", command_params[0]); + + /* VDVVRHEN (C2h): VDV and VRH Command Enable (== reset defaults) */ + command_params[0] = 0x01; /* CMDEN=1 (VDV and VDH command write enable */ + command_params[1] = 0xff; + lcd_ll_write_cmd(dev, LCD_CMD_VDVVRHEN, command_params, 2); + DEBUG("VDVVRHEN (C2h) %02x %02x\n", command_params[0], command_params[1]); + +#endif /* no need to write reset defaults, just for documentation purpose */ + +#if CONFIG_ST7789_CUSTOM_CONFIG + + /* VCOMS (BBh): VCOM Setting */ + command_params[0] = _st7789_calc_vcom(CONFIG_ST7789_VCOM); + lcd_ll_write_cmd(dev, LCD_CMD_VCOMS, command_params, 1); + DEBUG("VCOMS (BBh) %02x\n", command_params[0]); + + /* VRHS (C3h): VRH Set */ + command_params[0] = _st7789_calc_vrh(CONFIG_ST7789_VRH); + lcd_ll_write_cmd(dev, LCD_CMD_VRHS, command_params, 1); + DEBUG("VRHS (C3h) %02x\n", command_params[0]); + + /* VDVS (C4h): VDV Set */ + command_params[0] = _st7789_calc_vcom_offset_vdv(CONFIG_ST7789_VDV); + lcd_ll_write_cmd(dev, LCD_CMD_VDVS, command_params, 1); + DEBUG("VDVS (C4h) %02x\n", command_params[0]); + + /* VCMOFSET (C5h): VCOM Offset Set */ + command_params[0] = _st7789_calc_vcom_offset_vdv(CONFIG_ST7789_VCOM_OFFSET); + lcd_ll_write_cmd(dev, LCD_CMD_VCMOFSET, command_params, 1); + DEBUG("VCMOFSET (C5h) %02x\n", command_params[0]); + + /* PWCTRL1 (D0h): Power Control 1 */ + command_params[0] = 0xa4; + command_params[1] = (_st7789_calc_avdd(CONFIG_ST7789_AVDD) << 6) | + (_st7789_calc_avcl(CONFIG_ST7789_AVCL) << 4) | 0x01; + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1X, command_params, 2); + DEBUG("PWCTRL1 (D0h): %02x %02x\n", command_params[0], command_params[1]); + +#else /* CONFIG_ST7789_CUSTOM_CONFIG */ + +#if 0 /* no need to write reset defaults, just for documentation purpose */ + + /* VCOMS (BBh): VCOM Setting (== reset defaults) */ + command_params[0] = 0x20; /* VCOM=0.9V */ + lcd_ll_write_cmd(dev, LCD_CMD_VCOMS, command_params, 1); + + /* VRHS (C3h): VRH Set (== reset defaults) */ + command_params[0] = 0x0b; /* VRH=4.1V */ + lcd_ll_write_cmd(dev, LCD_CMD_VRHS, command_params, 1); + + /* VDVS (C4h): VDV Set (== reset defaults)*/ + command_params[0] = 0x20; /* VDV=0V */ + lcd_ll_write_cmd(dev, LCD_CMD_VDVS, command_params, 1); + + /* VCMOFSET (C5h): VCOM Offset Set (== reset defaults) */ + command_params[0] = 0x20; /* VCOMFS=0V */ + lcd_ll_write_cmd(dev, LCD_CMD_VCMOFSET, command_params, 1); + + /* PWCTRL1 (D0h): Power Control 1 (== reset defaults) */ + command_params[0] = 0xa4; + command_params[1] = 0xa1; /* AVDD=6.8V, AVCL=4.8V, VDS=2.3 */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1X, command_params, 2); + +#endif /* no need to write reset defaults, just for documentation purpose */ + +#endif /* CONFIG_ST7789_CUSTOM_CONFIG */ + +#if 0 /* no need to write reset defaults, just for documentation purpose */ + + /* FRCTRL2 (C6h): Frame Rate Control in Normal Mode */ + command_params[0] = 0x0f; /* == reset default (60 Hz) */ + lcd_ll_write_cmd(dev, LCD_CMD_FRCTRL2, command_params, 1); + DEBUG("FRCTRL2 (C6h) %02x\n", command_params[0]); + + /* PORCTRL (B2h): Porch Setting */ + command_params[0] = 0x0c; /* == reset defaults */ + command_params[1] = 0x0c; + command_params[2] = 0x00; + command_params[3] = 0x33; + command_params[4] = 0x33; + lcd_ll_write_cmd(dev, LCD_CMD_PORCTRL, command_params, 5); + + /* GCTRL (B7h): Gate Control */ + command_params[0] = 0x35; /* == reset defaults */ + lcd_ll_write_cmd(dev, LCD_CMD_GCTRL, command_params, 1); + +#endif /* no need to write reset defaults, just for documentation purpose */ + + /* VGAMCTRL (E0h): Positive Voltage Gamma Control */ + { + static const uint8_t gamma_pos[] = { + 0xd0, 0x08, 0x11, 0x08, 0x0c, 0x15, 0x39, + 0x33, 0x50, 0x36, 0x13, 0x14, 0x29, 0x2d + }; + lcd_ll_write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, sizeof(gamma_pos)); + } + /* NVGAMCTRL (E1h): Negative Voltage Gamma Control */ + { + static const uint8_t gamma_neg[] = { + 0xd0, 0x08, 0x10, 0x08, 0x06, 0x06, 0x39, + 0x44, 0x51, 0x0b, 0x16, 0x14, 0x2f, 0x32 + }; + lcd_ll_write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, sizeof(gamma_neg)); + } + + return 0; +} diff --git a/drivers/st77xx/st7796_init.c b/drivers/st77xx/st7796_init.c new file mode 100644 index 000000000000..8385d04b90e2 --- /dev/null +++ b/drivers/st77xx/st7796_init.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 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 + * directory for more details. + */ + +/** + * @ingroup drivers_st77xx + * @{ + * + * @file + * @brief Controller specific initialization for ST7796 + * + * @author Gunar Schorcht + * + * This file is only compiled if the `st7796` module is enabled. + * + * @} + */ + +#include +#include + +#include "byteorder.h" +#include "kernel_defines.h" +#include "ztimer.h" + +#include "st77xx.h" +#include "st7796_internal.h" +#include "lcd.h" +#include "lcd_internal.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if CONFIG_ST7796_CUSTOM_CONFIG +/* avdd in mV with 200 mV increments: 6600 = 6.6V + * Datasheet page 223: + * + * y = 0 for avdd < 6200 (< 6.2V) + * y = (avdd - 6200) / 200 for avdd = 6200 to 6800 (6.2 to 6.8V) + * y = 3 for avdd > 6800 (> 6.8V) + * + * default value after reset is 6.6 V (0x02) + */ +static inline uint8_t _st7796_calc_avdd(int16_t avdd) +{ + assert((avdd >= 6200) && (avdd <= 6800)); + assert((avdd % 200) == 0); + + return (avdd - 6200) / 200; +} + +/* avcl in mV with 200 mV increments: -4800 = -4.8V + * Datasheet page 223: + * + * y = 0 for avcl < -5000 (< -5.0V) + * y = 3 - ((avcl + 5000) / 200) for avcl = -5000 to -4400 (-5.0V to -4.4V) + * y = 3 for avcl > -4400 (> -4.4V) + * + * default value after reset is -4.4 V (0x00) + */ +static inline uint8_t _st7796_calc_avcl(int16_t avcl) +{ + assert((avcl >= -5000) && (avcl <= -4400)); + assert((avcl % 200) == 0); + + return 3 - ((avcl + 5000) / 200); +} + +/* vcom in mV with 25 mV increments: 1325 = 1.325V + * Datasheet page 227: + * + * y = 0 for vcom < 300 (< 0.3V) + * y = (vcom - 300) / 25 for vcom = 100 to 1875 (0.3V to 1.875V) + * y = 63 for vcom > 1685 (> 1.875V) + * + * default value after reset is 1.0V (0x1c) + */ +static inline uint8_t _st7796_calc_vcom(int16_t vcom) +{ + assert((vcom >= 300) && (vcom <= 1875)); + assert((vcom % 25) == 0); + + return (vcom - 300) / 25; +} + +/* vol in mV with 25 mV increments: 100 = 0.1V + * Datasheet page 229: + * + * y = 0 for vol < -800 (< -0.8V) + * y = (vol + 800) / 25 for vol = -800 to 775 (-0.8V to 0.775V) + * y = 63 for vol > 0.775 (> 0.775V) + * + * default value after reset is 0 V (0x00) + */ +static inline uint8_t _st7796_calc_vcom_offset(int16_t off) +{ + assert((off >= -800) && (off <= 775)); + assert((off % 25) == 0); + + return (off < 0) ? 32 + ((off + 800) / 25) : off / 25; +} + +/* vrh in mV with 50 mV increments: 4800 = 4.8V + * Datasheet page 224: + * + * y = 0 for vrh < 3550 (< 3.55V) + * y = (vrh - 3550) / 50 for vrh = 3550 to 5500 (3.55V to 5.5V) + * y = 39 for vrh > 5500 (> -4.4V) + * + * default value after reset is 4.5 V (0x13) + */ +static inline uint8_t _st7796_calc_vrh(int16_t vrh) +{ + assert((vrh >= 3550) && (vrh <= 5500)); + assert((vrh % 50) == 0); + + return (vrh - 3550) / 50; +} +#endif /* CONFIG_ST7796_CUSTOM_CONFIG */ + +int st7796_init(lcd_t *dev, const lcd_params_t *params) +{ + assert(params->lines <= 480); + assert(params->rgb_channels <= 320); + + uint8_t command_params[5] = { 0 }; + (void)command_params; + +#if CONFIG_ST7796_CUSTOM_CONFIG + + /* PWR1 (c0h): Power Control 1 */ + command_params[0] = (_st7796_calc_avdd(CONFIG_ST7796_AVDD) << 6) | + (_st7796_calc_avcl(CONFIG_ST7796_AVCL) << 4); + command_params[1] = 0x25; /* use reset default, TODO VGH and VGL config */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 2); + DEBUG("PWR1 (c0h): %02x %02x\n", command_params[0], command_params[1]); + + /* PWR2 (C1h): Power Control 2 */ + command_params[0] = _st7796_calc_vrh(CONFIG_ST7796_VRH); + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 1); + DEBUG("PWR2 (C1h) %02x\n", command_params[0]); + + /* VCMPCTL (C5h): VCOM Control */ + command_params[0] = _st7796_calc_vcom(CONFIG_ST7796_VCOM); + lcd_ll_write_cmd(dev, LCD_CMD_VCMPCTL, command_params, 1); + DEBUG("VCMPCTL (C5h) %02x\n", command_params[0]); + + /* VCM Offset (C6h): Vcom Offset Register */ + command_params[0] = _st7796_calc_vcom_offset(CONFIG_ST7796_VCOM_OFFSET); + lcd_ll_write_cmd(dev, LCD_CMD_VCM, command_params, 1); + DEBUG("VCM (C6h) %02x\n", command_params[0]); + +#else /* CONFIG_ST7796_CUSTOM_CONFIG */ + +#if 0 /* no need to write reset defaults, just for documentation purpose */ + + /* PWR1 (c0h): Power Control 1 (== reset defaults) */ + command_params[0] = 0x80; /* AVDD=6.6V, AVCL=-4.4 */ + command_params[1] = 0x25; /* use reset default, TODO VGH and VGL config */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL1, command_params, 2); + DEBUG("PWR1 (c0h): %02x %02x\n", command_params[0], command_params[1]); + + /* PWR2 (C1h): Power Control 2 (== reset defaults) */ + command_params[0] = 0x0b; /* VRH=4.1V */ + lcd_ll_write_cmd(dev, LCD_CMD_PWCTRL2, command_params, 1); + DEBUG("PWR2 (C1h) %02x\n", command_params[0]); + + /* VCMPCTL (C5h): VCOM Control (== reset defaults) */ + command_params[0] = 0x1c; /* VCOM=1.0V */ + lcd_ll_write_cmd(dev, LCD_CMD_VCMPCTL, command_params, 1); + DEBUG("VCMPCTL (C5h) %02x\n", command_params[0]); + + /* VCM Offset (C6h): Vcom Offset Register (== reset defaults) */ + command_params[0] = 0x00; /* VCOM Offset=0V (VMF_REG=0) */ + lcd_ll_write_cmd(dev, LCD_CMD_VCM, command_params, 1); + DEBUG("VCM (C6h) %02x\n", command_params[0]); + +#endif /* no need to write reset defaults, just for documentation purpose */ + +#endif /* CONFIG_ST7796_CUSTOM_CONFIG */ + + /* VGAMCTRL (E0h): Positive Voltage Gamma Control */ + { + static const uint8_t gamma_pos[] = { + 0xf0, 0x09, 0x0b, 0x06, 0x04, 0x15, 0x2f, + 0x54, 0x42, 0x3c, 0x17, 0x14, 0x18, 0x1b, + }; + lcd_ll_write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, sizeof(gamma_pos)); + } + /* NVGAMCTRL (E1h): Negative Voltage Gamma Control */ + { + static const uint8_t gamma_neg[] = { + 0xe0, 0x09, 0x0b, 0x06, 0x04, 0x03, 0x2b, + 0x43, 0x42, 0x3b, 0x16, 0x14, 0x17, 0x1b + }; + lcd_ll_write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, sizeof(gamma_neg)); + } + + return 0; +} diff --git a/drivers/st77xx/st77xx.c b/drivers/st77xx/st77xx.c index 4443ca3edc7b..48a02ae8d289 100644 --- a/drivers/st77xx/st77xx.c +++ b/drivers/st77xx/st77xx.c @@ -29,12 +29,12 @@ #include "kernel_defines.h" #include "ztimer.h" -#if IS_USED(MODULE_LCD_SPI) -#include "periph/spi.h" -#endif - #include "st77xx.h" #include "st77xx_internal.h" +#include "st7735_internal.h" +#include "st7789_internal.h" +#include "st7796_internal.h" + #include "lcd.h" #include "lcd_internal.h" @@ -43,72 +43,59 @@ static int _init(lcd_t *dev, const lcd_params_t *params) { - if (params->cntrl == ST77XX_CNTRL_ST7735) { - assert(params->lines <= 162); - assert(params->rgb_channels <= 132); - } - if (params->cntrl == ST77XX_CNTRL_ST7789) { - assert(params->lines <= 320); - assert(params->rgb_channels <= 240); - } - if (params->cntrl == ST77XX_CNTRL_ST7796) { - assert(params->lines <= 480); - assert(params->rgb_channels <= 320); - } - else { - assert(0); - } - - uint8_t command_params[4] = { 0 }; + uint8_t command_params[1] = { 0 }; /* Acquire once and release at the end */ lcd_ll_acquire(dev); - /* Soft Reset */ + /* Soft Reset (requires 120 ms if in Sleep In mode), default display off */ lcd_ll_write_cmd(dev, LCD_CMD_SWRESET, NULL, 0); ztimer_sleep(ZTIMER_MSEC, 120); - /* Display off */ - lcd_ll_write_cmd(dev, LCD_CMD_DISPOFF, NULL, 0); + /* Sleep Out command to leave Sleep In state after reset, requires 120 ms */ + lcd_ll_write_cmd(dev, LCD_CMD_SLPOUT, NULL, 0); + ztimer_sleep(ZTIMER_MSEC, 120); - /* TODO: instead of using a wrong initialization command sequence for power - * and frame control, default values after reset are used. */ + /* COLMOD (3Ah): Interface Pixel Format */ + command_params[0] = 0x55; /* 16 bit mode RGB & Control */ + lcd_ll_write_cmd(dev, LCD_CMD_COLMOD, command_params, 1); - /* Memory access CTL */ - command_params[0] = dev->params->rotation; - command_params[0] |= dev->params->rgb ? 0 : LCD_MADCTL_BGR; - lcd_ll_write_cmd(dev, LCD_CMD_MADCTL, command_params, 1); + /* controller specific initialization part called */ + if (IS_USED(MODULE_ST7735) && (params->cntrl == ST77XX_CNTRL_ST7735)) { + DEBUG("ST7735 used ...\n"); + st7735_init(dev, params); + } + else if (IS_USED(MODULE_ST7789) && (params->cntrl == ST77XX_CNTRL_ST7789)) { + DEBUG("ST7789 used ...\n"); + st7789_init(dev, params); + } + else if (IS_USED(MODULE_ST7735) && (params->cntrl == ST77XX_CNTRL_ST7735)) { + DEBUG("ST7735 used ...\n"); + st7735_init(dev, params); + } - /* Pixel format */ - command_params[0] = 0x55; /* 16 bit mode */ - lcd_ll_write_cmd(dev, LCD_CMD_PIXSET, command_params, 1); +#if 0 /* no need to write reset defaults, just for documentation purpose */ + /* GAMSET (26h): Gamma Set (== reset defaults) */ command_params[0] = 0x01; lcd_ll_write_cmd(dev, LCD_CMD_GAMSET, command_params, 1); - /* Gamma correction */ - { - static const uint8_t gamma_pos[] = { - 0xf0, 0x09, 0x0b, 0x06, 0x04, 0x15, 0x2f, - 0x54, 0x42, 0x3c, 0x17, 0x14, 0x18, 0x1b, - }; - lcd_ll_write_cmd(dev, LCD_CMD_PGAMCTRL, gamma_pos, - sizeof(gamma_pos)); - } - { - static const uint8_t gamma_neg[] = { - 0xe0, 0x09, 0x0b, 0x06, 0x04, 0x03, 0x2b, - 0x43, 0x42, 0x3b, 0x16, 0x14, 0x17, 0x1b - }; - lcd_ll_write_cmd(dev, LCD_CMD_NGAMCTRL, gamma_neg, - sizeof(gamma_neg)); - } + /* TEON (35h): Tearing Effect Line ON (== reset defaults) */ + command_params[0] = 0x00; /* TEM=0 (only V-Blanking) */ + lcd_ll_write_cmd(dev, LCD_CMD_VCOMS, command_params, 1); + +#endif /* no need to write reset defaults, just for documentation purpose */ + /* MADCTL (36h): Memory Data Access Control */ + command_params[0] = dev->params->rotation; + command_params[0] |= dev->params->rgb ? 0 : LCD_MADCTL_BGR; + lcd_ll_write_cmd(dev, LCD_CMD_MADCTL, command_params, 1); + + /* enable Inversion if configured, reset default is off */ if (dev->params->inverted) { + /* INVON (21h): Display Inversion On */ lcd_ll_write_cmd(dev, LCD_CMD_DINVON, NULL, 0); } - /* Sleep out (turn off sleep mode) */ - lcd_ll_write_cmd(dev, LCD_CMD_SLPOUT, NULL, 0); /* Normal display mode on */ lcd_ll_write_cmd(dev, LCD_CMD_NORON, NULL, 0); From 5c7a9cc9661d0936015f88a972116c3df3d67288 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Wed, 12 Jul 2023 16:47:00 +0200 Subject: [PATCH 2/3] drivers/lcd: assert controller-specific init function --- drivers/lcd/lcd.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/lcd/lcd.c b/drivers/lcd/lcd.c index 8abe50518902..1b7685fc36e1 100644 --- a/drivers/lcd/lcd.c +++ b/drivers/lcd/lcd.c @@ -184,12 +184,9 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) } ztimer_sleep(ZTIMER_MSEC, 120); - if (dev->driver->init) { - return dev->driver->init(dev, params); - } - else { - return -ENOTSUP; - } + /* controller-specific init function has to be defined */ + assert(dev->driver->init); + return dev->driver->init(dev, params); } void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, From 7599ce7b0024e90eb9170b2dc013281cdcab47f3 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Fri, 14 Jul 2023 00:27:05 +0200 Subject: [PATCH 3/3] drivers/st77xx: expose configuration parameters in Kconfig --- drivers/st77xx/Kconfig.st7735 | 68 +++++++++++++++++++++++++ drivers/st77xx/Kconfig.st7789 | 94 +++++++++++++++++++++++++++++++++++ drivers/st77xx/Kconfig.st7796 | 79 +++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+) diff --git a/drivers/st77xx/Kconfig.st7735 b/drivers/st77xx/Kconfig.st7735 index 62b6ad1e5240..ac2a80d6adea 100644 --- a/drivers/st77xx/Kconfig.st7735 +++ b/drivers/st77xx/Kconfig.st7735 @@ -13,4 +13,72 @@ config MODULE_ST7735 help ST7735 display controller is used +if MODULE_ST7735 + +menuconfig ST7735_CUSTOM_CONFIG + bool "ST7735 Custom Configuration" + help + Enable if customized configuration of voltages are needed. Otherwise + reset default values are used. + +if ST7735_CUSTOM_CONFIG + +config ST7735_AVDD + int "AVDD voltage (in millivolts)" + default 4900 + range 4500 5100 + help + Configure the AVDD voltage for analog circuits in millivolts. + Valid values must be in the range of 4500 (4.5V) to 5100 (5.1V) + in steps of 100. + +config ST7735_GVDD + int "GVDD voltage (in millivolts)" + default 4600 + range 3150 4700 + help + Configure the GVDD voltage, the gamma reference positive voltage. + Valid values must be in the range of 3150 (3.15V) to 4700 (4.7V) + in steps of 50. + +config ST7735_GVCL + int "GVCL voltage (in millivolts)" + default -4600 + range -4700 -3150 + help + Configure the GVCL voltage, the gamma reference negative voltage. + Valid values must be in the range of -4700 (-4.7V) to -3150 (-3.15V) + in steps of 50. + +config ST7735_VCOM + int "VCOM voltage (in millivolts)" + default -775 + range -2000 -425 + help + Configure the VCOM voltage. VCOM needs to be adjusted to match the + capacitance and performance specifications of the TFT panel to + maximize contrast and minimize flickering. + Valid values must be in the range of -2000 (-2.0V) to -425 (-0.425V) + in steps of 25. + +config ST7735_VGH + int "VGH voltage (in millivolts)" + default 14700 + range 10000 15000 + help + Configure the high voltage for gate drivers in millivolts. + Valid values must be in the range of 10000 (10V) to 15000 (15V) and + in the range of (2 * AVDD + 2.1V) and (3 * AVDD + 2.4 V). + +config ST7735_VGL + int "VGL voltage (in millivolts)" + default -10000 + range -13000 -7500 + help + Configure the low voltage for gate drivers in millivolts. + Valid values must be in the range of -13000 (-13V) to -7500 (-7.5V) + in steps of 2500. + +endif # ST7735_CUSTOM_CONFIG +endif # MODULE_ST7735 endif # MODULE_ST77XX diff --git a/drivers/st77xx/Kconfig.st7789 b/drivers/st77xx/Kconfig.st7789 index 7acbfd58a6ab..ba1e4a72094d 100644 --- a/drivers/st77xx/Kconfig.st7789 +++ b/drivers/st77xx/Kconfig.st7789 @@ -13,4 +13,98 @@ config MODULE_ST7789 help ST7789 display controller is used +if MODULE_ST7789 + +menuconfig ST7789_CUSTOM_CONFIG + bool "ST7789 Custom Configuration" + help + Enable if customized configuration of voltages are needed. Otherwise + reset default values are used. + +if ST7789_CUSTOM_CONFIG + +config ST7789_AVDD + int "AVDD voltage (in millivolts)" + default 6600 + range 6400 6800 + help + Configure the AVDD voltage for analog circuits in millivolts. + Valid values must be in the range of 6400 (6.4V) to 6800 (6.8V) + in steps of 200. + +config ST7789_AVCL + int "AVDD voltage (in millivolts)" + default -4400 + range -5000 -4400 + help + Configure the AVCL voltage in millivolts. + Valid values must be in the range of -5000 (-5V) to -4400 (-4.4V) + in steps of 200. + +config ST7789_VCOM + int "VCOM voltage (in millivolts)" + default 900 + range 100 1675 + help + Configure the VCOM voltage level. VCOM needs to be adjusted + to match the capacitance and performance specifications of the TFT panel + to maximize contrast and minimize flickering. VCOM is used to derive + the GVDD (gamma reference positive voltage) and the GVCL (gamma + reference negative voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + + Valid values must be in the range of 100 (0.1V) to 1675 (1.675V) + in steps of 25. + +config ST7789_VCOM_OFFSET + int "VCOM voltage offset (in millivolts)" + default 0 + range -800 775 + help + Configure the VCOM voltage offset (VCOM_OFFSET). VCOM_OFFSET is used to + derive the GVDD (gamma reference positive voltage) and the GVCL (gamma + reference negative voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + + Valid values must be in the range of -800 (-0.8V) to 775 (0.775V) + in steps of 25. + +config ST7789_VDV + int "VDV voltage offset factor (in millivolts)" + default 0 + range -800 775 + help + Configure the VDV voltage offset factor. VDV is used to derive the GVDD + (gamma reference positive voltage) and the GVCL (gamma reference + negative voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + + Valid values must be in the range of -800 (-0.8V) to 775 (0.775V) + in steps of 25. + +config ST7789_VRH + int "VRH voltage range (in millivolts)" + default 4100 + range 3550 5500 + help + Configure the VRH voltage range. VRH is used to derive the GVDD (gamma + reference positive voltage) and the GVCL (gamma reference negative + voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + + Valid values must be in the range of 3350 (3.35V) to 5500 (5.5V) + in steps of 50. + +# TODO ST7789_VGH and ST7789_VGL (non linear values) + +endif # ST7789_CUSTOM_CONFIG +endif # MODULE_ST7789 endif # MODULE_ST77XX diff --git a/drivers/st77xx/Kconfig.st7796 b/drivers/st77xx/Kconfig.st7796 index ce09399b1632..295f3ea2bf02 100644 --- a/drivers/st77xx/Kconfig.st7796 +++ b/drivers/st77xx/Kconfig.st7796 @@ -13,4 +13,83 @@ config MODULE_ST7796 help ST7796 display controller is used +if MODULE_ST7796 + +menuconfig ST7796_CUSTOM_CONFIG + bool "ST7796 Custom Configuration" + help + Enable if customized configuration of voltages are needed. Otherwise + reset default values are used. + +if ST7796_CUSTOM_CONFIG + +config ST7796_AVDD + int "AVDD voltage (in millivolts)" + default 6600 + range 6200 6800 + help + Configure the AVDD voltage for analog circuits in millivolts. + Valid values must be in the range of 6200 (6.2V) to 6800 (6.8V) + in steps of 200. + +config ST7796_AVCL + int "AVDD voltage (in millivolts)" + default -4400 + range -5000 -4400 + help + Configure the AVCL voltage in millivolts. + Valid values must be in the range of -5000 (-5V) to -4400 (-4.4V) + in steps of 200. + +config ST7796_VCOM + int "VCOM voltage (in millivolts)" + default 1000 + range 300 1875 + help + Configure the VCOM voltage level. VCOM needs to be adjusted to match + the capacitance and performance specifications of the TFT panel to + maximize contrast and minimize flickering. VCOM is used to derive the + GVDD (gamma reference positive voltage) and the GVCL (gamma reference + negative voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + GVCL = -VRH + VCOM + VCOM_OFFSET + + Valid values must be in the range of 300 (0.3V) to 1875 (1.875V) + in steps of 25. + +config ST7796_VCOM_OFFSET + int "VCOM voltage offset (in millivolts)" + default 0 + range -800 775 + help + Configure the VCOM voltage offset (VCOM_OFFSET). VCOM_OFFSET is used to + derive the GVDD (gamma reference positive voltage) and the GVCL (gamma + reference negative voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + GVCL = -VRH + VCOM + VCOM_OFFSET + + Valid values must be in the range of -800 (-0.8V) to 775 (0.775V) + in steps of 25. + +config ST7796_VRH + int "VRH voltage range (in millivolts)" + default 4500 + range 3550 5500 + help + Configure the VRH voltage range. VRH is used to derive the GVDD (gamma + reference positive voltage) and the GVCL (gamma reference negative + voltage) as follows: + + GDDV = +VRH + VCOM + VCOM_OFFSET + (0.5 * VDV) + GVCL = -VRH + VCOM + VCOM_OFFSET - (0.5 * VDV) + + Valid values must be in the range of 3350 (3.35V) to 5500 (5.5V) + in steps of 50. + +# TODO ST7796_VGH and ST7796_VGL (non linear values) + +endif # ST7796_CUSTOM_CONFIG +endif # MODULE_ST7796 endif # MODULE_ST77XX