drivers: display: st7735r: convert to MIPI DBI API

Convert the ST7735R display to use the MIPI DBI API. Boards and overlays
using this display are also updated.

Signed-off-by: Daniel DeGrasse <daniel.degrasse@nxp.com>
This commit is contained in:
Daniel DeGrasse 2024-03-21 14:26:28 -05:00 committed by Anas Nashif
commit 13ae32e1c2
5 changed files with 124 additions and 158 deletions

View file

@ -4,22 +4,26 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h>
/ {
chosen {
zephyr,display = &st7735r_st7735r_ada_160x128;
};
};
&arduino_spi {
status = "okay";
cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */
mipi_dbi_st7735r_ada_160x128 {
compatible = "zephyr,mipi-dbi-spi";
spi-dev = <&arduino_spi>;
dc-gpios = <&arduino_header 15 GPIO_ACTIVE_HIGH>; /* D9 */
reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
#address-cells = <1>;
#size-cells = <0>;
st7735r_st7735r_ada_160x128: st7735r@0 {
compatible = "sitronix,st7735r";
spi-max-frequency = <20000000>;
mipi-max-frequency = <20000000>;
mipi-mode = <MIPI_DBI_MODE_SPI_4WIRE>;
reg = <0>;
cmd-data-gpios = <&arduino_header 15 GPIO_ACTIVE_LOW>; /* D9 */
reset-gpios = <&arduino_header 14 GPIO_ACTIVE_LOW>; /* D8 */
width = <160>;
height = <128>;
x-offset = <0>;
@ -38,4 +42,10 @@
gamctrp1 = [02 1c 07 12 37 32 29 2d 29 25 2b 39 00 01 03 10];
gamctrn1 = [03 1d 07 06 2e 2c 29 2d 2e 2e 37 3f 00 00 02 10];
};
};
};
&arduino_spi {
status = "okay";
cs-gpios = <&arduino_header 16 GPIO_ACTIVE_LOW>; /* D10 */
};

View file

@ -5,6 +5,7 @@
*/
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h>
/ {
chosen {
@ -65,6 +66,50 @@
sw0 = &button_boot0;
watchdog0 = &fwdgt;
};
mipi_dbi {
compatible = "zephyr,mipi-dbi-spi";
reset-gpios = <&gpiob 1 GPIO_ACTIVE_LOW>;
dc-gpios = <&gpiob 0 GPIO_ACTIVE_HIGH>;
spi-dev = <&spi0>;
write-only;
#address-cells = <1>;
#size-cells = <0>;
/* longan nano has LCD with st7735s controller.
* It can use with st7735r driver.
*/
lcd0: lcd@0 {
compatible = "sitronix,st7735r";
reg = <0>;
status = "okay";
width = <160>;
height = <80>;
inversion-on;
rgb-is-inverted;
x-offset = <1>;
y-offset = <26>;
pwctr1 = [62 02 04];
pwctr2 = [C0];
pwctr3 = [0D 00];
pwctr4 = [8D 6A];
pwctr5 = [8D EE];
invctr = <3>;
frmctr1 = [05 3A 3A];
frmctr2 = [05 3A 3A];
frmctr3 = [05 3A 3A 05 3A 3A];
vmctr1 = <14>;
gamctrp1 = [10 0E 02 03 0E 07 02 07 0A 12 27 37 00 0D 0E 10];
gamctrn1 = [10 0E 03 03 0F 06 02 08 0A 13 26 36 00 0D 0E 10];
colmod = <5>;
madctl = <120>;
caset = [00 01 00 a0];
raset = [00 1a 00 69];
mipi-mode = <MIPI_DBI_MODE_SPI_4WIRE>;
mipi-max-frequency = <4000000>;
};
};
};
&gpioa {
@ -109,41 +154,6 @@
pinctrl-names = "default";
cs-gpios = <&gpiob 2 GPIO_ACTIVE_LOW>;
/* longan nano has LCD with st7735s controller.
* It can use with st7735r driver.
*/
lcd0: lcd@0 {
compatible = "sitronix,st7735r";
reg = <0>;
status = "okay";
reset-gpios = <&gpiob 1 GPIO_ACTIVE_LOW>;
cmd-data-gpios = <&gpiob 0 GPIO_ACTIVE_LOW>;
width = <160>;
height = <80>;
inversion-on;
rgb-is-inverted;
x-offset = <1>;
y-offset = <26>;
pwctr1 = [62 02 04];
pwctr2 = [C0];
pwctr3 = [0D 00];
pwctr4 = [8D 6A];
pwctr5 = [8D EE];
invctr = <3>;
frmctr1 = [05 3A 3A];
frmctr2 = [05 3A 3A];
frmctr3 = [05 3A 3A 05 3A 3A];
vmctr1 = <14>;
gamctrp1 = [10 0E 02 03 0E 07 02 07 0A 12 27 37 00 0D 0E 10];
gamctrn1 = [10 0E 03 03 0F 06 02 08 0A 13 26 36 00 0D 0E 10];
colmod = <5>;
madctl = <120>;
caset = [00 01 00 a0];
raset = [00 1a 00 69];
spi-max-frequency = <4000000>;
};
};
&spi1 {

View file

@ -7,6 +7,6 @@ config ST7735R
bool "ST7735R/ST7735S display driver"
default y
depends on DT_HAS_SITRONIX_ST7735R_ENABLED
select SPI
select MIPI_DBI
help
Enable driver for ST7735R/ST7735S display driver.

View file

@ -5,6 +5,7 @@
* Copyright (c) 2019 PHYTEC Messtechnik GmbH
* Copyright (c) 2020 Endian Technologies AB
* Copyright (c) 2020 Kim Bøndergaard <kim@fam-boendergaard.dk>
* Copyright 2024 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -14,7 +15,7 @@
#include "display_st7735r.h"
#include <zephyr/device.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/mipi_dbi.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/pm/device.h>
#include <zephyr/sys/byteorder.h>
@ -23,15 +24,14 @@
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(display_st7735r, CONFIG_DISPLAY_LOG_LEVEL);
#define ST7735R_RESET_TIME K_MSEC(1)
#define ST7735R_RESET_TIME 1
#define ST7735R_EXIT_SLEEP_TIME K_MSEC(120)
#define ST7735R_PIXEL_SIZE 2u
struct st7735r_config {
struct spi_dt_spec bus;
struct gpio_dt_spec cmd_data;
struct gpio_dt_spec reset;
const struct device *mipi_dev;
const struct mipi_dbi_config dbi_config;
uint16_t height;
uint16_t width;
uint8_t madctl;
@ -68,38 +68,13 @@ static void st7735r_set_lcd_margins(const struct device *dev,
data->y_offset = y_offset;
}
static void st7735r_set_cmd(const struct device *dev, int is_cmd)
{
const struct st7735r_config *config = dev->config;
gpio_pin_set_dt(&config->cmd_data, is_cmd);
}
static int st7735r_transmit_hold(const struct device *dev, uint8_t cmd,
const uint8_t *tx_data, size_t tx_count)
{
const struct st7735r_config *config = dev->config;
struct spi_buf tx_buf = { .buf = &cmd, .len = 1 };
struct spi_buf_set tx_bufs = { .buffers = &tx_buf, .count = 1 };
int ret;
st7735r_set_cmd(dev, 1);
ret = spi_write_dt(&config->bus, &tx_bufs);
if (ret < 0) {
return ret;
}
if (tx_data != NULL) {
tx_buf.buf = (void *)tx_data;
tx_buf.len = tx_count;
st7735r_set_cmd(dev, 0);
ret = spi_write_dt(&config->bus, &tx_bufs);
if (ret < 0) {
return ret;
}
}
return 0;
return mipi_dbi_command_write(config->mipi_dev, &config->dbi_config,
cmd, tx_data, tx_count);
}
static int st7735r_transmit(const struct device *dev, uint8_t cmd,
@ -109,7 +84,7 @@ static int st7735r_transmit(const struct device *dev, uint8_t cmd,
int ret;
ret = st7735r_transmit_hold(dev, cmd, tx_data, tx_count);
spi_release_dt(&config->bus);
mipi_dbi_release(config->mipi_dev, &config->dbi_config);
return ret;
}
@ -133,11 +108,8 @@ static int st7735r_reset_display(const struct device *dev)
int ret;
LOG_DBG("Resetting display");
if (config->reset.port != NULL) {
gpio_pin_set_dt(&config->reset, 1);
k_sleep(ST7735R_RESET_TIME);
gpio_pin_set_dt(&config->reset, 0);
} else {
ret = mipi_dbi_reset(config->mipi_dev, ST7735R_RESET_TIME);
if (ret != 0) {
ret = st7735r_transmit(dev, ST7735R_CMD_SW_RESET, NULL, 0);
if (ret < 0) {
return ret;
@ -204,12 +176,12 @@ static int st7735r_write(const struct device *dev,
{
const struct st7735r_config *config = dev->config;
const uint8_t *write_data_start = (uint8_t *) buf;
struct spi_buf tx_buf;
struct spi_buf_set tx_bufs;
uint16_t write_cnt;
uint16_t nbr_of_writes;
uint16_t write_h;
int ret;
enum display_pixel_format fmt;
struct display_buffer_descriptor mipi_desc;
__ASSERT(desc->width <= desc->pitch, "Pitch is smaller than width");
__ASSERT((desc->pitch * ST7735R_PIXEL_SIZE * desc->height)
@ -225,9 +197,24 @@ static int st7735r_write(const struct device *dev,
if (desc->pitch > desc->width) {
write_h = 1U;
nbr_of_writes = desc->height;
mipi_desc.height = 1;
mipi_desc.buf_size = desc->pitch * ST7735R_PIXEL_SIZE;
} else {
write_h = desc->height;
nbr_of_writes = 1U;
mipi_desc.height = desc->height;
mipi_desc.buf_size = desc->width * ST7735R_PIXEL_SIZE * write_h;
}
mipi_desc.width = desc->width;
/* Per MIPI API, pitch must always match width */
mipi_desc.pitch = desc->width;
if (!(config->madctl & ST7735R_MADCTL_BGR) != !config->rgb_is_inverted) {
fmt = PIXEL_FORMAT_BGR_565;
} else {
fmt = PIXEL_FORMAT_RGB_565;
}
ret = st7735r_transmit_hold(dev, ST7735R_CMD_RAMWR,
@ -237,14 +224,13 @@ static int st7735r_write(const struct device *dev,
goto out;
}
tx_bufs.buffers = &tx_buf;
tx_bufs.count = 1;
write_data_start += (desc->pitch * ST7735R_PIXEL_SIZE);
for (write_cnt = 1U; write_cnt < nbr_of_writes; ++write_cnt) {
tx_buf.buf = (void *)write_data_start;
tx_buf.len = desc->width * ST7735R_PIXEL_SIZE * write_h;
ret = spi_write_dt(&config->bus, &tx_bufs);
ret = mipi_dbi_write_display(config->mipi_dev,
&config->dbi_config,
write_data_start,
&mipi_desc,
fmt);
if (ret < 0) {
goto out;
}
@ -254,7 +240,7 @@ static int st7735r_write(const struct device *dev,
ret = 0;
out:
spi_release_dt(&config->bus);
mipi_dbi_release(config->mipi_dev, &config->dbi_config);
return ret;
}
@ -445,36 +431,11 @@ static int st7735r_init(const struct device *dev)
const struct st7735r_config *config = dev->config;
int ret;
if (!spi_is_ready_dt(&config->bus)) {
LOG_ERR("SPI bus %s not ready", config->bus.bus->name);
if (!device_is_ready(config->mipi_dev)) {
LOG_ERR("MIPI bus %s not ready", config->mipi_dev->name);
return -ENODEV;
}
if (config->reset.port != NULL) {
if (!gpio_is_ready_dt(&config->reset)) {
LOG_ERR("Reset GPIO port for display not ready");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&config->reset,
GPIO_OUTPUT_INACTIVE);
if (ret) {
LOG_ERR("Couldn't configure reset pin");
return ret;
}
}
if (!gpio_is_ready_dt(&config->cmd_data)) {
LOG_ERR("cmd/DATA GPIO port not ready");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&config->cmd_data, GPIO_OUTPUT);
if (ret) {
LOG_ERR("Couldn't configure cmd/DATA pin");
return ret;
}
ret = st7735r_reset_display(dev);
if (ret < 0) {
LOG_ERR("Couldn't reset display");
@ -530,11 +491,13 @@ static const struct display_driver_api st7735r_api = {
#define ST7735R_INIT(inst) \
const static struct st7735r_config st7735r_config_ ## inst = { \
.bus = SPI_DT_SPEC_INST_GET( \
inst, SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | \
.mipi_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)), \
.dbi_config = MIPI_DBI_CONFIG_DT_INST(inst, \
SPI_OP_MODE_MASTER | \
((DT_INST_PROP(inst, mipi_mode) == \
MIPI_DBI_MODE_SPI_4WIRE) ? SPI_WORD_SET(8) : \
SPI_WORD_SET(9)) | \
SPI_HOLD_ON_CS | SPI_LOCK_ON, 0), \
.cmd_data = GPIO_DT_SPEC_INST_GET(inst, cmd_data_gpios), \
.reset = GPIO_DT_SPEC_INST_GET_OR(inst, reset_gpios, {}), \
.width = DT_INST_PROP(inst, width), \
.height = DT_INST_PROP(inst, height), \
.madctl = DT_INST_PROP(inst, madctl), \

View file

@ -5,26 +5,9 @@ description: ST7735R/ST7735S 160x128 (max) display controller
compatible: "sitronix,st7735r"
include: [spi-device.yaml, display-controller.yaml]
include: [mipi-dbi-spi-device.yaml, display-controller.yaml]
properties:
reset-gpios:
type: phandle-array
description: RESET pin.
The RESET pin of ST7735R is active low.
If connected directly the MCU pin should be configured
as active low.
cmd-data-gpios:
type: phandle-array
required: true
description: D/CX pin.
The D/CX pin of ST7735R is active low (transmission command byte).
If connected directly the MCU pin should be configured
as active low.
x-offset:
type: int
required: true