(WIP) Sitronix ST7735 TFT Display

Discuss development of drivers for external hardware and components, such as LCD screens, sensors, motor drivers, etc.
Target audience: Users and developers of drivers.
Peter.Kenyon
Posts: 70
Joined: Wed Oct 14, 2015 5:07 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by Peter.Kenyon » Tue Jun 21, 2016 5:46 am

well I guessed that it was a typo on the backing field, the ability to replace the function with a simple assignment is a powerful tool ?, (adults only coding)
@platforma : similar in backlight I believe
ps got the ghi n18 up and running, had to configure the spi correctly and init is different (as you point out)

User avatar
platforma
Posts: 258
Joined: Thu May 28, 2015 5:08 pm
Location: Japan

Re: (WIP) Sitronix ST7735 TFT Display

Post by platforma » Tue Jun 21, 2016 11:32 am

Thanks for pointing out the bug! Now fixed. Also looking into the suggested font techniques.

Peter.Kenyon
Posts: 70
Joined: Wed Oct 14, 2015 5:07 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by Peter.Kenyon » Wed Jun 22, 2016 7:25 am

wrt fonts one technique I found quite useful is to store bitmap images of antialiased fonts on the sd card,.
This presupposes you know the background color and foreground color, but there is plenty of room for lucida green 24 say and Helvetica alice blue 12, and nowadays most displays should be uncluttered on a neutral background (black)
The file contains all the glyphs and on init you rip thro and build up a seek table for the character.
To display a character just seek to the offset, set the window to the cx and cy and then blit the rgb565 chars.
here is a snippet...

Code: Select all

def draw_image(f,x,y):
    print("need to read the header and then blit to the screen")
    print(f, x, y)

# static helper to store/cache the fonts
class Fonts:

    _segoe14 = None
    _segoe16 = None
    _segoe24 = None
    _segoe36 = None

    @staticmethod
    def Segoe14():
        if Fonts._segoe14 is None:
            Fonts._segoe14 = Font('segoe-14.gff')
        return Fonts._segoe14

    @staticmethod
    def Segoe16():
        if Fonts._segoe16 is None:
            Fonts._segoe16 = Font('segoe-16.gff')
        return Fonts._segoe16

    @staticmethod
    def Segoe24():
        if Fonts._segoe24 is None:
            Fonts._segoe24 = Font('segoe-24.gff')
        return Fonts._segoe24

    @staticmethod
    def Segoe36():
        if Fonts._segoe36 is None:
            Fonts._segoe36 = Font('segoe-36.gff')
        return Fonts._segoe36

    @staticmethod
    def Load():
        # preload fonts we want to avoid delays - can take some time
        Fonts.Segoe14()
        Fonts.Segoe16()
        Fonts.Segoe24()
        Fonts.Segoe36()


class Font(object):

    def __init__(self, filename):
        # save the filename for multiple use
        self._filename = filename
        # open read glpyh info and close
        with open(filename, 'rb') as f:
            # generate lookup table - takes a little while
            self.table = {}
            index = 0
            for c in range(32, 127):
                r = f.seek(index)
                header = f.read(4)
                w = header[0]*256 + header[1]
                h = header[2]*256 + header[3]
                self.table[chr(c)] = (w,h,index)
                index += 6 + w * h * 2
        # save some meta data about this font
        self.emwidth, self.font_height = self.measure('M')
        self.line_height = self.font_height + 1  ## ??
        self.f = None

    def open(self):
        self.f = open(self._filename, 'rb')
        return self

    def release(self):
        if self.f:
            self.f.close()
            #del self.f
            self.f = None

    def __enter__(self):
        return self.open()

    def __exit__(self, type, value, traceback):
        self.release()

    def draw_text(self, x, y, text, align='left'):
        # check self.f is not None
        if not self.f:
            raise ValueError('draw_text not called in an open context')
        if align == 'center':
            w, h = self.measure(text)
            x -= w // 2
        elif align == 'right':
            w, h = self.measure(text)
            x -= w
        elif align != 'left':
            raise ValueError("align should be 'left', 'center' or 'right'")
        for c in text:
            w, h, index = self.table[c]
            self.f.seek(index)
            r = draw_image(self.f, x, y)
            x += w
        pass

    # doesnt require the file to be open to do this
    def measure(self, text):
        width, height = 0, 0
        for c in text:
            w, h, index = self.table[c]
            width += w
            height = max(height, h)
        return width, height

    def __del__(self):
        self.release()


User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by deshipu » Wed Jun 22, 2016 7:35 am

It's actually not that hard to blend an ant-ialiased font with an RGB pixel value, treating the original greymap as the alpha channel, and using any foreground color you want.

Peter.Kenyon
Posts: 70
Joined: Wed Oct 14, 2015 5:07 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by Peter.Kenyon » Wed Jun 22, 2016 7:51 am

I'm guessing that you could store a glyph table with byte values representing weight ie 255 is full on and 0 is transparent.
Then you could use a run time algortithm to blend into the background display, but sounds quite tricky and would need a backing buffer or are you suggesting something completely different

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by deshipu » Wed Jun 22, 2016 8:21 am

No, that's precisely what I meant by "alpha channel".

Sure, you either need a frame buffer, or a way to retrieve the pixels from the display itself (e.g. MISO wire connected) to be able to do blending -- after all, you need to know what pixels are there somehow. But you can also fall back to assuming a background color, and then you basically get the same thing you initially suggested.

As for being tricky, I'm not sure it's really that complex. I mean, Bresenham's line drawing algorithm is trickier, but everyone do it anyways.

Peter.Kenyon
Posts: 70
Joined: Wed Oct 14, 2015 5:07 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by Peter.Kenyon » Wed Jun 22, 2016 8:34 am

for efficiency I guess the glyph table would only need to be 2 or 4 bits per pixel,
Is it really as simple as : new pixel = ((1-weight) * old) + (weight*color) ??
Sounds like a challenge ;-)
Bresenham's line drawing algorithm is straightforward BUT not if you want to ant alias the jaggies

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by deshipu » Wed Jun 22, 2016 9:27 am

Peter.Kenyon wrote: Is it really as simple as : new pixel = ((1-weight) * old) + (weight*color)?
It can even be simpler, depending on the exact result desired:

Code: Select all

new pixel = min(limit, old + weight * color)
(yes, won't work for dark too well)

User avatar
pythoncoder
Posts: 5956
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: (WIP) Sitronix ST7735 TFT Display

Post by pythoncoder » Thu Jun 23, 2016 4:09 pm

Peter.Kenyon wrote:wrt fonts one technique I found quite useful is to store bitmap images of antialiased fonts on the sd card...
There is a potential performance issue here: performing a file random access for every character can be slow. I've used this approach for driving ePaper displays where the device is inherently slow, but found it to be a problem with faster displays. Hence my suggestion of writing a utility to convert a font to Python source (a bytes object plus a minimal amount of extra code such as font metrics) which can then be frozen as bytecode. In my testing this is provides performance with minimal ram usage.
Peter Hinch
Index to my micropython libraries.

Peter.Kenyon
Posts: 70
Joined: Wed Oct 14, 2015 5:07 pm

Re: (WIP) Sitronix ST7735 TFT Display

Post by Peter.Kenyon » Fri Jun 24, 2016 7:10 am

good point, but not seen any problems yet, but only updating a few things now and again, not a scrolling console window or anything.

Post Reply