80x160 TFT display with the nrf9160 on SPI and ST7735 driver

nRF connect SDK v 2.1.1 using visual studio code.

Hei  

A few busy weeks here, however I've finally tested some more in regards to previous question found under your guide on the forum: 
small-i2c-oled-displays-using-nrf-connect-sdk

To summarize the problem Im trying to get a 160x80 pixel (Width x Height) TFT display with the ST3375 driver to work with the nrf9160 over SPI. 
The specific display can be found here: TFT 160x80 SPI - RS components

Ive tested the TFT with an ESP32-C3 mini in the Arduino environment and confirmed that the display is working fine with same wiring as used for the nrf9160 setup.

For the nrf9160 setup, upon probing the SPI signals I see that MOSI, CLK, CS, RESET and CMD pins are giving nice 3v3 signals. (I had to switch the RESET and CMD pins from the previous gpio0 8 and gpio0 9 as these did not produce any output.

However the result I get on the TFT display is still just garbage.
Ive played around with lowering the SPI max frequency but without any luck.

I can see that the idle state of the data signal (MOSI)  is 3v3 as opposed to 0v in the ESP32 test. I don't think the problem lays here, but just as a note, what would be the best way to define CPOL/CPHA in code when using the ST7735 driver. Would this be done in the .overlay file?


TFT alive but not making sense.



The above is the first byte clocked in when writing to the TFT display. 



The above shows the command (CMD) signal in blue and the CLK signal in yellow around midways in a SPI write session. 

The .overlay code:

 / {
	chosen {
		zephyr,display = &st7735r_st7735r_ada_160x128;
	};
};

&arduino_spi {
	compatible = "nordic,nrf-spim";
	status = "okay";
	cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* D10 */
	pinctrl-0 = <&spi3_default>;
	pinctrl-1 = <&spi3_sleep>;
	pinctrl-names = "default", "sleep";

	st7735r_st7735r_ada_160x128: st7735r@0 {
		compatible = "sitronix,st7735r";
		spi-max-frequency = <250000>;
		reg = <0>;
		cmd-data-gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;	
		reset-gpios = <&gpio0 20  GPIO_ACTIVE_LOW>;
		width = <160>;
		height = <80>;
		x-offset = <0>;
		y-offset = <0>;
		madctl = <0x60>;
		colmod = <0x55>;
		vmctr1 = <0x0e>;
		pwctr1 = [a2 02 84];
		pwctr2 = [c5];
		pwctr3 = [0a 00];
		pwctr4 = [8a 2a];
		pwctr5 = [8a ee];
		frmctr1 = [01 2c 2d];
		frmctr2 = [01 2c 2d];
		frmctr3 = [01 2c 2d 01 2c 2d];
		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];
	};
};

The prj.conf code:

CONFIG_LV_Z_MEM_POOL_NUMBER_BLOCKS=8
CONFIG_MAIN_STACK_SIZE=2048

CONFIG_DISPLAY=y
CONFIG_SPI=y

CONFIG_ST7735R=y
CONFIG_DISPLAY_LOG_LEVEL_ERR=y

CONFIG_LOG=y

CONFIG_LVGL=y
CONFIG_LV_MEM_CUSTOM=y
CONFIG_LV_USE_LOG=y
CONFIG_LV_USE_LABEL=y
CONFIG_LV_USE_BTN=y
CONFIG_LV_USE_IMG=y
CONFIG_LV_FONT_MONTSERRAT_14=y

CONFIG_LV_Z_BITS_PER_PIXEL=16

The main src: 

/*
 * Copyright (c) 2018 Jan Van Winkel <[email protected]>
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/device.h>
#include <zephyr/drivers/display.h>
#include <lvgl.h>
#include <stdio.h>
#include <string.h>
#include <zephyr/zephyr.h>
#include <sys/printk.h>

#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(app);

void main(void)
{
	uint32_t count = 0U;
	char count_str[11] = {0};
	const struct device *display_dev;
	lv_obj_t *hello_world_label;
	lv_obj_t *count_label;

	display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));
	if (!device_is_ready(display_dev)) {
		LOG_ERR("Device not ready, aborting test");
		printk("Could not get %s device\n", display_dev);
		return;
	}

	if (IS_ENABLED(CONFIG_LV_Z_POINTER_KSCAN)) {
		lv_obj_t *hello_world_button;

		hello_world_button = lv_btn_create(lv_scr_act());
		lv_obj_align(hello_world_button, LV_ALIGN_CENTER, 0, 0);
		hello_world_label = lv_label_create(hello_world_button);
	} else {
		hello_world_label = lv_label_create(lv_scr_act());
	}

	lv_label_set_text(hello_world_label, "Hello world!");
	lv_obj_align(hello_world_label, LV_ALIGN_CENTER, 0, 0);

	count_label = lv_label_create(lv_scr_act());
	lv_obj_align(count_label, LV_ALIGN_BOTTOM_MID, 0, 0);

	lv_task_handler();
	display_blanking_off(display_dev);

	while (1) {
		if ((count % 100) == 0U) {
			sprintf(count_str, "%d", count/100U);
			lv_label_set_text(count_label, count_str);
			printk("Updated display\n");
		}
		lv_task_handler();
		k_sleep(K_MSEC(10));
		++count;
	}
}


Any help leading to a working display would be highly appreciated.

Best regards 
Tor

  • Hi Tor,

    Just letting you know I have received the case. I will take a look at get back to you.

    Best regards,

    Håkon

  • what would be the best way to define CPOL/CPHA in code when using the ST7735 driver.

    Please see the flags in the SPI API. Some SPI flags are defined in the ST7735 driver. As CPOL/CPHA are not defined here, they are likely not needed. However, it would not hurt to give it a try.

    I noticed that your display module is populated with ST7735S, however, the driver you are using is named st7735r. There are three parts from Sitronix with similar names, ST7735, ST7735R and ST7735S. I do not know exactly what the differences are and whether it is causing any problems.

    Ive tested the TFT with an ESP32-C3 mini in the Arduino environment and confirmed that the display is working fine with same wiring as used for the nrf9160 setup.

    Is this driver specifically written for the -R or the -S version?

    However the result I get on the TFT display is still just garbage.

    Is the garbage the same every time? Does it keep changing when the application is running?

  • Have you checked the terminal to see if there are any error messages?

  • Hi again Håkon,

    I have the terminal printing "updated display" once every second. From main.c  we see that this is after we have a screen write/update. No errors printed.

    About the difference of the R and S version I have reached out to Sitronix for a comment.
    Some of the differences are listed here: https://www.sitronix.com.tw/en/products/aiot-device-ddi/

    In regards to the adafruit library Its a bit difficult to decipher if its written for a specific version. Code and comment are somewhat contradicting Adafruit-ST7735.

    However since the MCU seems to be writing data on the SPI bus, and we have something going on on the screen (prints different versions of garbage to the screen on the first few updates before turning blank - see first picture in post for what I refer to as garbage). I though to look into the format of the actual data written. 

    Ive compared the Adafruit library for the "INITR_MINI160x80" as this is the settings that works for the display using the ESP32. The .overlay file is changed slightly in order to replicate the Adafruit driver settings: Adafruit-ST7735

    The following is now in the .overlay file:

     / {
    	chosen {
    		zephyr,display = &st7735r_st7735r_ada_160x128;
    	};
    };
    
    &arduino_spi {
    	compatible = "nordic,nrf-spim";
    	status = "okay";
    	cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* D10 */
    	pinctrl-0 = <&spi3_default>;
    	pinctrl-1 = <&spi3_sleep>;
    	pinctrl-names = "default", "sleep";
    
    	st7735r_st7735r_ada_160x128: st7735r@0 {
    		compatible = "sitronix,st7735r";
    		spi-max-frequency = <1000000>;
    		reg = <0>;
    		cmd-data-gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;	
    		reset-gpios = <&gpio0 20  GPIO_ACTIVE_LOW>;
    		width = <80>;
    		height = <160>;
    		x-offset = <0>;
    		y-offset = <0>;
    		madctl = <0xC0>;
    		colmod = <0x05>;
    		caset = [00 00 00 4F];
    		raset = [00 00 00 9F];
    		vmctr1 = <0x0e>;
    		invctr = <0x07>;
    		pwctr1 = [a2 02 84];
    		pwctr2 = [c5];
    		pwctr3 = [0a 00];
    		pwctr4 = [8a 2a];
    		pwctr5 = [8a ee];
    		frmctr1 = [01 2c 2d];
    		frmctr2 = [01 2c 2d];
    		frmctr3 = [01 2c 2d 01 2c 2d];
    		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];
    	};
    };

    Ive added the:

    caset = [00 00 00 4F];
    raset = [00 00 00 9F];
    invctr = <0x07>;

    and changed

    madctl = <0xC0>;
    colmod = <0x05>;


    The display is however still printing garbage the first few updates before turning blank.  


Related