element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Raspberry Pi
  • Products
  • More
Raspberry Pi
Raspberry Pi Forum RPI Pico & ST7789 Display
  • Blog
  • Forum
  • Documents
  • Quiz
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Raspberry Pi to participate - click to join for free!
Featured Articles
Announcing Pi
Technical Specifications
Raspberry Pi FAQs
Win a Pi
Raspberry Pi Wishlist
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 15 replies
  • Subscribers 661 subscribers
  • Views 16458 views
  • Users 0 members are here
  • st7789
  • rpi pico
Related

RPI Pico & ST7789 Display

scottiebabe
scottiebabe over 3 years ago

I purchased an off brand ST7789 1.3" Display a few months ago and recently decided it was time to try it out.

 

I did not realize it at the time but there isn't a consistent pinout between display boards. As it turns out the board I purchased did not pin out the chip-select (CS) line.

 

The ST7789 display driver will function without a CS line, however you need to configure the SPI mode (idle state, edge polarity) to communicate with the display. In most cases, I suppose that would be easy enough to change the display driver.

 

Now I wanted to make use of this display with a PI Pico and Micropython. Pimoroni provide a Micropython release with a small number additional libraries on top of MicroPython : https://github.com/pimoroni/pimoroni-pico (unlike CircuitPython which is significantly different from MicroPython).

 

I was trying to get their example code for one of their displays: https://shop.pimoroni.com/products/1-3-spi-colour-lcd-240x240-breakout to function with my off brand display. Unfortunately, I could not find a way to change the SPI operating mode of the display driver unless I wanted to compile their distribution from source (which I didn't want to do), the SPI initialization was all buried in C code.

 

An intsructables author provided a wonderful guide to breaking out the chip-select line: https://www.instructables.com/Adding-CS-Pin-to-13-LCD/  Many thanks. In the process of modify my display I learned a few things the hard way:

  • Rotated R1 90' to bypass the NPN switch
  • Tossed R2 away and used this as the CS pad
  • Be carful with getting the display too hot. The adhesive that held the display in place virtually no longer exists now image
  • Be carful cleaning! Or don't clean at all. I ended up relocating the flux residue with isopropyl from the PCB to inside the display housing and its now a little merky image

image

 

After the display modifications the display came to life!

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

I have never used one of these displays before, but I have to say I am impressed. I was able to get 35 FPS out of a 240x240 display running over SPI.

 

I still don't know what the best way to add graphics to the PICO is. The image I showed in the video was created with ffmpeg outputting a raw video frame:

 

ffmpeg -vcodec png -i img.png -vcodec rawvideo -f rawvideo -pix_fmt rgb565 img.raw

 

Of this random image cropped down to 240x240:

image

Loading the image from flash was very slow.

 

Update: Image Loading Speed

The framebuffer for the ST7789 is stored big-endian so when I was loading the Image I had endian swap in python which was really slow. I can endian swap the raw image file format using dd:

dd conv=swab if=img.raw of=img2.raw

Now loading the image is now significantly faster:

t1 = time.ticks_us()
with open('img2.raw', 'rb') as f:
    for j in range(0,240,24):
        display_buffer[480*j:(480*(j+24))] = f.read(240*48)

display.update() # only update display once now, remove those tabs!
print((time.ticks_us() - t1)/1000)

 

Which now runs in 232 ms 85 ms and appears more as a transition animation versus terribly slow code.

 

Update: Overclocking in MicroPython

One can adjust the system clock frequency in MicroPython by issuing the following command:

machine.freq(190_000_000) # set system clock in Hz

 

When MicroPython alters the system clock frequency, it also reconfigures the peripheral clock source from clk_sys to the external crystal oscillator.

image

 

So, if you want to maintain a high-speed SPI clock frequency, you need to set the clock mux back to clk_sys yourself by:

mem32[0x40008000+0x48] = 0x800

 

With the Pico running at 190 MHz I achieved the following:

     Rainbow Spinner: 53 FPS

     FFT Demo: 16 FPS

     Image Load + Draw: 56 ms (49ms letting the garbage collector run before the load)

 

Of course, there are no guarantees this will always work for every Pico and or display.

  • Sign in to reply
  • Cancel
Parents
  • scottiebabe
    scottiebabe over 3 years ago

    FFT Display Demo: FPS ~ 10

     

    Micropython Release: MicroPython with Pimoroni Libs (1010KB) - https://github.com/pimoroni/pimoroni-pico/releases/download/v0.2.7/pimoroni-pico-v0.2.7-micropython-v1.16.uf2

    With Inspiration from: https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/examples/breakout_colourlcd240x240/demo.py

     

    This is just a quick lash-up to try out the NumPy (ulab) implementation on a RPI Pico. Considering most of these calculations are done as single precision floats on a processor with no floating point support and in python, the results are reasonable enough.

     

    from machine import Pin, SPI, mem32
    import time
    import random
    import math
    from ulab import numpy as np
    from random import random as randf
    from breakout_colourlcd240x240 import BreakoutColourLCD240x240
    np.set_printoptions(threshold=1000)
    
    rst = Pin(13,Pin.OUT)
    rst.value(1)
    
    width = BreakoutColourLCD240x240.WIDTH
    height = BreakoutColourLCD240x240.HEIGHT
    
    display_buffer = bytearray(width * height * 2)  # 2-bytes per pixel (RGB565)
    display = BreakoutColourLCD240x240(display_buffer)
    display.set_pen(255, 255, 255)  # Set pen to white
    display.clear()           # Fill the screen with the colour
    mem32[0x4003c000] = 0x007
    
    N = 256 # FFT Length
    
    # Synthesize Hanning FFT Window
    win = 0.5*(1 - np.cos(2*math.pi*np.array(range(1,N+1))/(N+1)))
    W = np.fft.fft(win)
    Wgain = sum((W[0]**2 + W[1]**2))/N**2;
    del(W)
    
    def RandWinFTT(Omega):
        noise = np.array([ randf() for i in range(N) ] )
        sig = np.array([ 10*math.sin(i*Omega) for i in range(N) ])
        yy = sig + noise
        yy = yy * win
        YY = np.fft.fft(yy)
    
        YMag = ((YY[0]**2 + YY[1]**2)**(1/2))*2/N/Wgain
        YMagdB = 20*np.log10(YMag)
        
        return np.array(YMagdB[0:int(N/2+1)],dtype=np.int8)
    
    t1 = time.ticks_us()
    fps=float('nan')
    i = 0
    while True:
        display.set_pen(255, 194, 232)  # Set pen to white
        display.clear()           # Fill the screen with the colour
        display.set_pen(0, 0, 0)  # Set pen to black
        display.text("FFT 256", 10, 10, 240, 6)  # Add some text
        display.text("FPS: {:1.1f}".format(fps), 10, 50, 240, 6)  # Add some text
        
        d = random.uniform(1,128)
        Y = RandWinFTT(math.pi*d/128)
        display.set_pen(0, 0, 0)  # Set pen to black
        xo = 50
        yo = 200
        
        idxmin = Y < -40.0; Y[idxmin] = -40.0
        idxmax = Y > 30.0; Y[idxmax] = 30.0
        Ys = Y  + 40.0
        for x in range(128):
            h = int(Ys[x])
            if h > 71:
                raise Exception('How!?')
            display.rectangle(xo+x,200-h,1,h)
            
        tm = time.localtime()
        display.text("{:02d}:{:02d}:{:02d}".format(tm[3],tm[4],tm[5]), 10, 220, 240, 3)  # Display Time
        display.text('Scottie',160,225,240,2)
        display.update()          # Update the display
        
        if i == 0:
            fps = 10/(time.ticks_us()-t1)*1e6
            t1 = time.ticks_us()
        i = (i+1) % 10

     

    There is some funny business with array indexing, sometimes the assignment doesn't take. Not sure if that's me or ulab.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Reply
  • scottiebabe
    scottiebabe over 3 years ago

    FFT Display Demo: FPS ~ 10

     

    Micropython Release: MicroPython with Pimoroni Libs (1010KB) - https://github.com/pimoroni/pimoroni-pico/releases/download/v0.2.7/pimoroni-pico-v0.2.7-micropython-v1.16.uf2

    With Inspiration from: https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/examples/breakout_colourlcd240x240/demo.py

     

    This is just a quick lash-up to try out the NumPy (ulab) implementation on a RPI Pico. Considering most of these calculations are done as single precision floats on a processor with no floating point support and in python, the results are reasonable enough.

     

    from machine import Pin, SPI, mem32
    import time
    import random
    import math
    from ulab import numpy as np
    from random import random as randf
    from breakout_colourlcd240x240 import BreakoutColourLCD240x240
    np.set_printoptions(threshold=1000)
    
    rst = Pin(13,Pin.OUT)
    rst.value(1)
    
    width = BreakoutColourLCD240x240.WIDTH
    height = BreakoutColourLCD240x240.HEIGHT
    
    display_buffer = bytearray(width * height * 2)  # 2-bytes per pixel (RGB565)
    display = BreakoutColourLCD240x240(display_buffer)
    display.set_pen(255, 255, 255)  # Set pen to white
    display.clear()           # Fill the screen with the colour
    mem32[0x4003c000] = 0x007
    
    N = 256 # FFT Length
    
    # Synthesize Hanning FFT Window
    win = 0.5*(1 - np.cos(2*math.pi*np.array(range(1,N+1))/(N+1)))
    W = np.fft.fft(win)
    Wgain = sum((W[0]**2 + W[1]**2))/N**2;
    del(W)
    
    def RandWinFTT(Omega):
        noise = np.array([ randf() for i in range(N) ] )
        sig = np.array([ 10*math.sin(i*Omega) for i in range(N) ])
        yy = sig + noise
        yy = yy * win
        YY = np.fft.fft(yy)
    
        YMag = ((YY[0]**2 + YY[1]**2)**(1/2))*2/N/Wgain
        YMagdB = 20*np.log10(YMag)
        
        return np.array(YMagdB[0:int(N/2+1)],dtype=np.int8)
    
    t1 = time.ticks_us()
    fps=float('nan')
    i = 0
    while True:
        display.set_pen(255, 194, 232)  # Set pen to white
        display.clear()           # Fill the screen with the colour
        display.set_pen(0, 0, 0)  # Set pen to black
        display.text("FFT 256", 10, 10, 240, 6)  # Add some text
        display.text("FPS: {:1.1f}".format(fps), 10, 50, 240, 6)  # Add some text
        
        d = random.uniform(1,128)
        Y = RandWinFTT(math.pi*d/128)
        display.set_pen(0, 0, 0)  # Set pen to black
        xo = 50
        yo = 200
        
        idxmin = Y < -40.0; Y[idxmin] = -40.0
        idxmax = Y > 30.0; Y[idxmax] = 30.0
        Ys = Y  + 40.0
        for x in range(128):
            h = int(Ys[x])
            if h > 71:
                raise Exception('How!?')
            display.rectangle(xo+x,200-h,1,h)
            
        tm = time.localtime()
        display.text("{:02d}:{:02d}:{:02d}".format(tm[3],tm[4],tm[5]), 10, 220, 240, 3)  # Display Time
        display.text('Scottie',160,225,240,2)
        display.update()          # Update the display
        
        if i == 0:
            fps = 10/(time.ticks_us()-t1)*1e6
            t1 = time.ticks_us()
        i = (i+1) % 10

     

    There is some funny business with array indexing, sometimes the assignment doesn't take. Not sure if that's me or ulab.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube