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.

  • 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?

  • Hello 

    I an working with same st7789 tft 240x240 display but i'dont have idea which library file need for this display configuration so can you please help me to give some reference or give library file so that i can start it 

Related