From 40a3e600a9be0f2ab2f543e1a0fb0e220d45b672 Mon Sep 17 00:00:00 2001 From: Marc Reilly Date: Mon, 15 Jul 2019 18:41:09 +0100 Subject: [PATCH] samples: display: add a simple sample for st7789v display This adds a basic app which puts some rectangles on the display It's hard to write an equivalent README to the rest of the sample documentation, as the LCD I have uses a custom board thrown together for testing. (ie other LCDs have publicly available modules) Signed-off-by: Marc Reilly --- samples/display/st7789v/CMakeLists.txt | 7 + samples/display/st7789v/README.rst | 60 ++++++ .../display/st7789v/nrf52_pca10040.overlay | 25 +++ samples/display/st7789v/prj.conf | 15 ++ samples/display/st7789v/sample.yaml | 8 + samples/display/st7789v/src/main.c | 172 ++++++++++++++++++ 6 files changed, 287 insertions(+) create mode 100644 samples/display/st7789v/CMakeLists.txt create mode 100644 samples/display/st7789v/README.rst create mode 100644 samples/display/st7789v/nrf52_pca10040.overlay create mode 100644 samples/display/st7789v/prj.conf create mode 100644 samples/display/st7789v/sample.yaml create mode 100644 samples/display/st7789v/src/main.c diff --git a/samples/display/st7789v/CMakeLists.txt b/samples/display/st7789v/CMakeLists.txt new file mode 100644 index 00000000000..d6553c14b91 --- /dev/null +++ b/samples/display/st7789v/CMakeLists.txt @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(st7789v) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/display/st7789v/README.rst b/samples/display/st7789v/README.rst new file mode 100644 index 00000000000..2ae96d293ac --- /dev/null +++ b/samples/display/st7789v/README.rst @@ -0,0 +1,60 @@ +.. _st7789v-sample: + +ST7789V Display driver +###################### + +Overview +******** +This sample will draw some basic rectangles onto the display. +The rectangle colors and positions are chosen so that you can check the +orientation of the LCD and correct RGB bit order. The rectangles are drawn +in clockwise order, from top left corner: Red, Green, Blue, grey. The shade of +grey changes from black through to white. (if the grey looks too green or red +at any point then the LCD may be endian swapped). + +Note: The display driver rotates the display so that the 'natural' LCD +orientation is effectively 270 degrees clockwise of the default display +controller orientation. + +Building and Running +******************** +The sample has a board overlay for a nrf52832 based board with the following +pin assignments: + ++-------------+-------------+ +| | nRF52832 | | LCD module| +| | Pin | | signal | ++=============+=============+ +| P0.03 | SPI_SCK | ++-------------+-------------+ +| P0.05 | SPI_MOSI | ++-------------+-------------+ +| P0.26 | SPI_MISO | ++-------------+-------------+ +| P0.27 | CS | ++-------------+-------------+ +| P0.25 | DATA/CMD | ++-------------+-------------+ +| P0.02 | RESET | ++-------------+-------------+ + +You might need to alter these according to your specific board/LCD configuration. + +For :ref:`nrf52_pca10040`, build this sample application with the following commands: + +.. zephyr-app-commands:: + :zephyr-app: samples/display/st7789v + :board: nrf52_pca10040 + :goals: build + :compact: + +See :ref:`nrf52_pca10040` on how to flash the build. + + +References +********** + +- `ST7789V datasheet`_ + +.. _Manufacturer site: https://www.sitronix.com.tw/en/product/Driver/mobile_display.html +.. _ST7789V datasheet: https://www.crystalfontz.com/controllers/Sitronix/ST7789V/ diff --git a/samples/display/st7789v/nrf52_pca10040.overlay b/samples/display/st7789v/nrf52_pca10040.overlay new file mode 100644 index 00000000000..83ac9647066 --- /dev/null +++ b/samples/display/st7789v/nrf52_pca10040.overlay @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Creative Product Design + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&spi0 { + status = "okay"; + sck-pin = <3>; + mosi-pin = <5>; + miso-pin = <26>; + cs-gpios = <&gpio0 27 0>; + + st7789v@0 { + compatible = "sitronix,st7789v"; + label = "DISPLAY"; + spi-max-frequency = <20000000>; + reg = <0>; + cmd-data-gpios = <&gpio0 25 0>; + reset-gpios = <&gpio0 2 0>; + width = <320>; + height = <170>; + y-offset = <35>; + }; +}; diff --git a/samples/display/st7789v/prj.conf b/samples/display/st7789v/prj.conf new file mode 100644 index 00000000000..ba0d9d4d91d --- /dev/null +++ b/samples/display/st7789v/prj.conf @@ -0,0 +1,15 @@ +CONFIG_PRINTK=y + +CONFIG_HEAP_MEM_POOL_SIZE=16384 + +CONFIG_GPIO=y +CONFIG_SPI=y + +CONFIG_DISPLAY=y +CONFIG_ST7789V=y +CONFIG_ST7789V_LCD_TL019FQV01=y +CONFIG_ST7789V_RGB565=y + +CONFIG_DISPLAY_LOG_LEVEL_DBG=y + +CONFIG_LOG=y diff --git a/samples/display/st7789v/sample.yaml b/samples/display/st7789v/sample.yaml new file mode 100644 index 00000000000..a555591b24a --- /dev/null +++ b/samples/display/st7789v/sample.yaml @@ -0,0 +1,8 @@ +sample: + description: Sample application for ST7789V display + name: st7789v_sample +tests: + sample.display.st7789v: + build_only: true + platform_whitelist: nrf52_pca10040 + tags: display \ No newline at end of file diff --git a/samples/display/st7789v/src/main.c b/samples/display/st7789v/src/main.c new file mode 100644 index 00000000000..cdf3aa090a2 --- /dev/null +++ b/samples/display/st7789v/src/main.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2019 Marc Reilly + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +LOG_MODULE_REGISTER(app, LOG_LEVEL_INF); + +#include +#include +#include + +static void backlight_init(void) +{ + /* If you have a backlight, set it up and turn it on here */ +} + +void main(void) +{ + LOG_INF("ST7789V display sample"); + struct device *display_dev; + + struct display_capabilities capabilities; + struct display_buffer_descriptor buf_desc; + + backlight_init(); + +#ifdef CONFIG_ST7789V_RGB565 + const size_t rgb_size = 2; +#else + const size_t rgb_size = 3; +#endif + + display_dev = device_get_binding(DT_INST_0_SITRONIX_ST7789V_LABEL); + + if (display_dev == NULL) { + LOG_ERR("Device not found. Aborting test."); + return; + } + + display_get_capabilities(display_dev, &capabilities); + + /* size of the rectangle */ + const size_t w = 40; + const size_t h = 20; + const size_t buf_size = rgb_size * w * h; + + /* points are clockwise, from top left */ + size_t x0, y0, x1, y1, x2, y2, x3, y3; + + /* top left */ + x0 = 0; + y0 = 0; + /* top right */ + x1 = capabilities.x_resolution - w; + y1 = 0; + /* bottom right */ + x2 = capabilities.x_resolution - w; + y2 = capabilities.y_resolution - h; + /* bottom left */ + x3 = 0; + y3 = capabilities.y_resolution - h; + + /* Allocate rectangular buffer for corner data */ + u8_t *buf = k_malloc(buf_size); + + if (buf == NULL) { + LOG_ERR("Could not allocate memory. Aborting test."); + return; + } + + /* Clear frame buffer before enabling LCD, reuse corner buffer + */ + int h_step; + (void)memset(buf, 0, buf_size); + h_step = (w * h) / capabilities.x_resolution; + + buf_desc.buf_size = buf_size; + buf_desc.pitch = capabilities.x_resolution; + buf_desc.width = capabilities.x_resolution; + buf_desc.height = h_step; + + for (int idx = 0; idx < capabilities.y_resolution; idx += h_step) { + display_write(display_dev, 0, idx, &buf_desc, buf); + } + + display_blanking_off(display_dev); + + buf_desc.pitch = w; + buf_desc.width = w; + buf_desc.height = h; + + int grey_count = 0; + size_t cnt = 0; + + while (1) { + /* Update the color of the rectangle buffer and write the buffer + * to one of the corners + */ +#ifdef CONFIG_ST7789V_RGB565 + int color = cnt % 4; + /* RGB565 format */ + u16_t color_r; + u16_t color_g; + u16_t color_b; + u16_t color_rgb; + + color_r = (color == 0) ? 0xF800U : 0U; + color_g = (color == 1) ? 0x07E0U : 0U; + color_b = (color == 2) ? 0x001FU : 0U; + color_rgb = color_r + color_g + color_b; + if (color == 3) { + u16_t t = grey_count & 0x1f; + /* shift the green an extra bit, it has 6 bits */ + color_rgb = t << 11 | t << (5+1) | t; + grey_count++; + } + + for (size_t idx = 0; idx < buf_size; idx += rgb_size) { + *(buf + idx + 0) = (color_rgb >> 8) & 0xFFU; + *(buf + idx + 1) = (color_rgb >> 0) & 0xFFU; + } +#else + u32_t color_rgb; + u32_t c = grey_count & 0xff; + + switch (cnt % 4) { + case 0: + color_rgb = 0x00FF0000u; + break; + case 1: + color_rgb = 0x0000FF00u; + break; + case 2: + color_rgb = 0x000000FFu; + break; + case 3: + color_rgb = c << 16 | c << 8 | c; + grey_count++; + break; + } + + /* RGB888 format */ + for (size_t idx = color; idx < buf_size; idx += rgb_size) { + *(buf + idx + 0) = color_rgb >> 16; + *(buf + idx + 1) = color_rgb >> 8; + *(buf + idx + 2) = color_rgb >> 0; + } +#endif + + switch (cnt % 4) { + case 0: + /* top left, red */ + display_write(display_dev, x0, y0, &buf_desc, buf); + break; + case 1: + /* top right, green */ + display_write(display_dev, x1, y1, &buf_desc, buf); + break; + case 2: + /* bottom right, blue */ + display_write(display_dev, x2, y2, &buf_desc, buf); + break; + case 3: + /* bottom left, alternating grey */ + display_write(display_dev, x3, y3, &buf_desc, buf); + break; + } + ++cnt; + k_sleep(100); + } +}