1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/st77xx/st7735_init.c
2023-09-22 17:00:00 +02:00

263 lines
9.1 KiB
C

/*
* 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 <gunar@schorcht.net>
*
* This file is only compiled if the `st7735` module is enabled.
*
* @}
*/
#include <assert.h>
#include <string.h>
#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)
{
(void)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;
}