This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Controlling ST7789 LCD with NRF52 DK

I am working on a project that requires an LCD and the one I have found is a 240x240px 1.54" LCD from Adafruit (Product ID 3787 https://www.adafruit.com/product/3787 ). I'm communicating with it over SPI and I am powering it externally from my NRF52 DK (NRF52832). I have the NRF5 SDK v.14.2.0 and have been trying to use the external driver .c file included in "\components\drivers_ext\st7735" for the ST7735 LCD driver with some luck. It took a while testing to find defining the tab color in the "sdk_config.h" as green, calling "nrf_gfx_rotation_set(p_lcd, NRF_LCD_ROTATE_180);" after initializing the GFX library, and calling "nrf_gfx_invert(p_lcd, true);" allows me to draw graphics and text on the screen appropriately (correct location, entire screen not partial, correct colors, etc.). I test this with drawing pixels and lines to confirm I could move the pointer up, down, left, and right as expected and can draw lines from one corner all the way to the other exactly. I am not completely sure of all the differences between the ST7789 that my LCD is using and the ST7735 that the NRF library is written for, and believe that I'm running into a slowdown issue related to this. Writing a line of five bold characters to the screen takes almost an entire second as it draws each character and drawing over the entire screen with a single color takes over a full second.

I have searched and not found an ST7789 library like the ST7735 one included in the NRF5 SDK made by Nordic. The ST7789's datasheet looks like it has multiple different commands from the ST7735's datasheet so I am unsure how I would go about rewriting the library to command the ST7789 more effectively. I looked through application responses from Adafruit for other LCDs of people complaining about slow refresh rates and the usual response is that the SPI bus speed is a bottleneck, although I have changed the define "SPI_DEFAULT_FREQUENCY" in the "sdk_config.h" between 8Mhz and 1Mhz as well as gone into "st7735.c" to change the SPI frequency when it calls "err_code = nrf_drv_spi_init(&spi, &spi_config, NULL, NULL);" to initialize the SPI and I did not see any notable difference in the refresh rate. I'm trying to use write and erase techniques like Matthew McMillan used in his blog ( http://matthewcmcmillan.blogspot.com/2014/08/arduino-tft-lcd-display-refresh-rate-part2.html ) to write over a character with itself the same color as the background then place the new character in its spot as the text color to try to reduce the amount of pixels being drawn, which has helped a lot but has't fully fixed my issue. I'm sure there are even more efficient ways of drawing new characters but this method is simple to implement and immediately cut my draw time considerably as it use to be even longer.

Ideally I want to be able to update up to four bold characters at a time without any noticeable draw time as I intend to include a clock counter on the screen and will periodically be updating smaller text entire strings of up to 32 characters. We do NOT want to replace the LCD we have as the color, brightness, dimensions, and resolution are perfect for our application so if there is any better way to be controlling an ST7789 with the NRF52 DK that would be excellent.

Thanks for any help!

Edit: I have also tested the NRF5 SDK 14.2.0's included external driver for the ILI9341 and it also seems at least partly compatible with the ST7789. I can draw the same characters, pixels, graphics, etc. using the same color inversion and rotation, the only notable difference being the colors aren't organized RGB they're BGR so my reds and blues are reversed. I have a simple timer also included and using it I estimated that with "ILI9341.c" defining the SPI clock speed as 4MHz it takes ~7.67 seconds from initialization through drawing multiple characters and graphics (just some testing I had, the graphics aren't final or important for now) and when I altered the file to define it as 8MHz the same process took ~6.96 seconds. There is some improvement but I don't believe that the SPI bus is what is holding up the drawing speed. I also noticed on the Nordic Infocenter there is a section in the GFX Library about the LCD's frame buffer being faster ( http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v14.2.0/lib_gfx.html?cp=4_0_2_3_18_3#gfx_lib_frame_buffer ). It says to use functions for pixel drawing, rectangle drawing, and LCD display updating, and from what I found the included libraries both already use pixel and rectangle drawing if you follow the function calls back to the "st7735.c" and "ili9341.c" files and in both the display function is called "dummy" and is left empty with the comment "/* No implementation needed. */". I am not sure if or how I would be able to use either of these to fully fix my refresh rate speed but it seems like a step in the right direction.

Parents
  • Hi

    Unfortunately, we're limited to what we can help you with since we don't have any official drivers for that LCD. Maybe the Adafruit help forum is a better place for getting help regarding that LCD screen: https://forums.adafruit.com/

    Good Luck

    Jared

  • Thanks Jared,

    I'll work towards implementing the Adafruit library for the ST7789 onto the NRF52. Originally I started prototyping this with a different LCD, their smaller TFT (Product ID 3533 https://www.adafruit.com/product/3533 ) and an Arduino UNO but since we needed both a higher resolution and wireless communication I moved to the NRF52 DK. It's odd that I managed to get the display at least partially functioning with the given code considering it's intended for a different driver. I've read that many LCD drivers like the ST7735, ILI9341, ST7781, etc. use some sort of standard but have variation in how they're initialized, certain commands, etc. (bottom of the page suggests close equivalents for the driver https://www.ramtex.dk/display-controller-driver/rgb/st7789.htm ). I've also read the Adafruit library is not particularly optimized ( https://github.com/XarkLabs/PDQ_GFX_Libs ) and that's mostly why I was staying away from it and switching over to Nordic libraries but if I absolutely need a library designed for my specific driver type I'll work with what I can get. I'll post updates here on my status and any issues I run into trying to get the Adafruit code working.

    Thanks

  • Also I added in that the frame buffer method only almost always writes faster because in specific situations the default NRF GFX method will be faster, specifically for drawing character with small numbers of pixels like very thin and small fonts or, most regularly, punctuation. Since something like a colon has so few pixels drawn relative to its total area, even when sending 6.5 times as much data per pixel if the number of pixels being drawn is less than the character's (width*height*8pixels/B / 6.5) it will end up sending fewer total bytes over SPI. I still use the default "nrf_gfx_print" function to draw certain small texts and characters like the clock's colon because of this. It's just that the default Nordic libraries were not efficient at drawing large characters to the screen like I needed to do.

  • Hi Andy, would you be so kind and share your final version. We try to use a display with ST7789 aswell. Thanks

  • Hi Constantin,

    Here's some code from when I was working with drawing two different examples onto the screen: ST7789 test code.zip .

    Since I modified my gfx library to make the screen work how I wanted it to it would be a good idea to copy the original, unmodified library from your SDK and keep it somewhere in case you need to modify the library even further and then something breaks. There were still a few bugs in my code, such as the program crashing if text would be drawn out of bounds vertically instead of just returning in that function. Sorry it's a few days late but I hope this helps you out.

  • Hi Andy,

    thank you for sharing this! I am also using the ST7789 display driver and your test code helped me a lot. I resolved a bug, where a display rotation of 0° was not working with a 240x240 display. It is quite simple, you have to edit the file st7789.c at three points.

    After

    //Position setting for 240x240 LCD
    #define ST7789_240x240_XSTART 0
    #define ST7789_240x240_YSTART 80

    insert the variables storing the offset:

    uint16_t x_offset = 0;
    uint16_t y_offset = 0;

    in function set_addr_window, 4 lines have to be added where the offset is added to the address window:

    static void set_addr_window(uint16_t x_0, uint16_t y_0, uint16_t x_1, uint16_t y_1)
    {
        ASSERT(x_0 <= x_1);
        ASSERT(y_0 <= y_1);
    
        // Adaption for rotation
        y_0 += y_offset;
        y_1 += y_offset;
        x_0 += x_offset;
        x_1 += x_offset;    
    
        write_command(ST7789_CASET);
        write_data(x_0 >> 8);
        write_data(x_0);
        write_data(x_1 >> 8);
        write_data(x_1);
        write_command(ST7789_RASET);
        write_data(y_0 >> 8);
        write_data(y_0);
        write_data(y_1 >> 8);
        write_data(y_1);
        write_command(ST7789_RAMWR);
    }

    and in function st7789_rotation_set the offset has to be set:

    static void st7789_rotation_set(nrf_lcd_rotation_t rotation)
    {
        write_command(ST7789_MADCTL);
        switch (rotation % 4) {
            case NRF_LCD_ROTATE_0:
                write_data(ST7789_MADCTL_MX | ST7789_MADCTL_MY | ST7789_MADCTL_RGB);  //Not working correctly
                //Column address (MX): Right to left
                //Page address (MY): Bottom to top
                //Page/ Column order (MV): normal
                //RGB/BGR order: RGB
                x_offset = 0;
                y_offset = ST7789_240x240_YSTART;
                break;
            case NRF_LCD_ROTATE_90:
                write_data(ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
                //Column address (MX): Left to right
                //Page address (MY): Top to bottom
                //Page/ Column order (MV): reverse
                //RGB/BGR order: RGB
                x_offset = 0;
                y_offset = 0;
                break;
            case NRF_LCD_ROTATE_180:
                write_data(ST7789_MADCTL_RGB);
                //Column address (MX): Left to right
                //Page address (MY): Top to bottom
                //Page/ Column order (MV): normal
                //RGB/BGR order: RGB
                x_offset = 0;
                y_offset = 0;
                break;
            case NRF_LCD_ROTATE_270:
                write_data(ST7789_MADCTL_MX | ST7789_MADCTL_MV | ST7789_MADCTL_RGB);
                //Column address (MX): Right to left
                //Page address (MY): Top to bottom
                //Page/ Column order (MV): reverse
                //RGB/BGR order: RGB
                x_offset = 0;
                y_offset = 0;
                break;
            default:
                break;
        }
    }

    That's it!

    Maybe you already solved it yourself, but for future users this could be helpful.

    Greetings

    Walther

  • Hi I am also used ST7789 tft display but different part.

    Can you please tell that your code is working fine with our display?

Reply Children
No Data
Related