011 - MicroPython TechNotes: 1.3 OLED Display

Introduction

Previously, we learned on how to use the 0.96 inch OLED display with MicroPython language and we use an external driver library named ssd1306.py. Now in this tutorial, we will look at the identical but a little bigger display which is the 1.3 inch OLED display and it uses an SH1106 driver chip. It has a monochrome display resolution which is 128×64 pixels.

Bill Of Materials

  1. ESP32 development board.
  2. Gorillacell ESP32 shield.
  3. 4-pin female-female Dupont jumper wires.
  4. 1.3 OLED display.

Pinout

  1. GND – for the ground pin.
  2. VCC – for the supply voltage.
  3. SDA – for the i2c serial data pin.
  4. SCL – for the i2c serial clock pin.

Hardware Instruction

  1. First, attach the ESP32 development board at the top of Gorillacell ESP32 shield and make sure that both USB port are on the same side.
  2. Next, attach the dupont wire to the 1.3 OLED display by following the color coding which is black for the ground, red for the VCC, yellow for the SDA, and white for the SCL pin.
  3. Next, attach the other side of the dupont wire to the ESP32 shield by matching the colors of the wires to the colors of the pin headers which is black to black, red to red, yellow and the following colors to yellow pin headers. For this experiment, I choose GPIO 21 for the SDA pin and GPIO 22 for the SCL pin.
  4. Next, power the ESP32 shield by attaching an external power supply with a type-C USB cable and make sure that the power switch is slide to ON state.
  5. Next, connect the ESP32 to the computer by attaching a micro USB cable. The demo circuit should be ready by now.

Software Instruction

  1. Now to make our life easier, we will use an ready-made driver library for the 1.3 OLED display which is the SH106 by Robert Hammelrath and originally developed by Radomir Dopieralski:
    https://github.com/robert-hh/SH1106/blob/master/sh1106.py. You may also copy it below under the SOURCE CODE SECTION for your convenience.
  2. Now copy and save the sh1106.py to Thonny Python IDE and save it to MicroPython’s root directory by clicking the File menu and select Save As.
  3. Click MicroPython device and save it as sh1106.py.
  4. Repeat #2 and #3 to copy the following files from Peter Hinch font-to-py library for the custom font: https://github.com/peterhinch/micropython-font-to-py especially for the writer_minimal.py as a module for displaying custom font and the freesans20.py as the custom font. You may also copy it below under the SOURCE CODE SECTION for your convenience.
  5. Now check if you successfully save the file on ESP32 by clicking the View menu and select File. The newly save file should be seen under the MicroPython device.
  6. Please feel free to try each example given or you may play along with the video tutorial.
  7. Also, try to modify the example according to your liking and most of all, enjoy learning.

Video Demonstration

Call To Action

For any concern, write your message in the comment section.

You might also like to support my journey on Youtube by Subscribing. Click this to Subscribe to TechToTinker.

Thank you and have a good days ahead.

See you,

– George Bantique | tech.to.tinker@gmail.com

Source Code

1. Example # 1, for exploring basic functions you can do with the OLED display:

 1# More details can be found in TechToTinker.blogspot.com 
 2# George Bantique | tech.to.tinker@gmail.com
 3
 4from machine import Pin, I2C
 5from sh1106 import SH1106_I2C
 6
 7i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000) 
 8oled = SH1106_I2C(128, 64, i2c, None, addr=0x3C)
 9oled.sleep(False)
10
11# The following codes should be tested using the REPL.
12# #1. To print a string:  
13# oled.text('Hello world', 0, 0)
14# #2. To display all the commands in queue:     
15# oled.show() 
16# #3. Now to clear the oled display:  
17# oled.fill(0) 
18# oled.show() 
19# #4. You may also use the invert function to invert the display.  
20# oled.invert(1) 
21# #5.To display a single pixel.  
22# oled.pixel(10,20,1) 
23# oled.show() 
24# #6. To display a horizontal line  
25# oled.hline(30,40,10,1) 
26# oled.show() 
27# #7. To display a vertical line  
28# oled.vline(30,45,5,1) 
29# oled.show() 
30# #8. While hline and vline is quite useful, there is another function that is more flexible to use which is the line function.  
31# oled.line(0,50,10,50,1) 
32# oled.show() 
33# #9.We may also be able to print a rectangle.  
34# oled.rect(10,60,10,5,1) 
35# oled.show() 
36# #10. Or we may also print a filled rectangle:  
37# oled.fill_rect(10,70,10,5,1) 
38# oled.show()

2. Example # 2, display date and time using the ESP32 internal RTC module:

 1# More details can be found in TechToTinker.blogspot.com 
 2# George Bantique | tech.to.tinker@gmail.com
 3
 4from machine import Pin 
 5from machine import I2C 
 6from machine import RTC 
 7from time import sleep_ms 
 8from machine import Pin, I2C
 9from sh1106 import SH1106_I2C
10
11i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000) 
12oled = SH1106_I2C(128, 64, i2c, None, addr=0x3C)
13oled.sleep(False)
14
15rtc = RTC() 
16rtc.datetime((2021, 2, 6, 6, 19, 44, 0, 0)) 
17# rtc.datetime((YYYY, MM, DD, WD, HH, MM, SS, MS)) 
18# WD 1 = Monday 
19# WD 7 = Sunday 
20isPoint = True
21
22while True: 
23    t = rtc.datetime() 
24    oled.fill(0) 
25    oled.text('** 1.3 OLED **', 4, 0) 
26    oled.text('Date: {}-{:02d}-{:02d}' .format(t[0],t[1],t[2]), 0, 25)  
27    if isPoint: 
28        colon = ':' 
29    else: 
30        colon = ' ' 
31    oled.text('Time: {:02d}{}{:02d}' .format(t[4], colon, t[5]), 0, 40) 
32    oled.show() 
33    sleep_ms(500) 
34    isPoint = not isPoint

3. Example # 3, for exploring the basics of custom font:

 1# More details can be found in TechToTinker.blogspot.com 
 2# George Bantique | tech.to.tinker@gmail.com
 3
 4from machine import Pin, I2C
 5from sh1106 import SH1106_I2C
 6import freesans20
 7from writer_minimal import Writer
 8
 9i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000) 
10oled = SH1106_I2C(128,64,i2c,None,addr=0x3C)
11
12# create a writer instance
13font_writer = Writer(oled, freesans20)
14# set writing position
15font_writer.set_textpos(0, 0)
16# write some text!
17font_writer.printstring("hello")
18
19oled.show()

4. Example # 4, applying custom font to display date and time using the ESP32 internal RTC module:

 1# More details can be found in TechToTinker.blogspot.com 
 2# George Bantique | tech.to.tinker@gmail.com
 3
 4from machine import Pin, I2C
 5from sh1106 import SH1106_I2C
 6import freesans20
 7from writer_minimal import Writer
 8from machine import RTC 
 9from time import sleep_ms
10
11i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000) 
12oled = SH1106_I2C(128, 64, i2c, None, addr=0x3C)
13font_writer = Writer(oled, freesans20)
14
15rtc = RTC() 
16rtc.datetime((2021, 2, 10, 3, 11, 30, 0, 0)) 
17# rtc.datetime((YYYY, MM, DD, WD, HH, MM, SS, MS)) 
18# WD 1 = Monday 
19# WD 7 = Sunday 
20isPoint = True
21
22while True: 
23    t = rtc.datetime() 
24    oled.fill(0) 
25    oled.text('** 1.3 OLED **', 10, 0) 
26    # Display the date
27    font_writer.set_textpos(20, 15)
28    font_writer.printstring('{}-{:02d}-{:02d}' .format(t[0],t[1],t[2]))
29    if isPoint: 
30        colon = ':' 
31    else: 
32        colon = ' '
33    # Display the time
34    font_writer.set_textpos(40, 40)
35    font_writer.printstring('{:02d}{}{:02d}' .format(t[4], colon, t[5]))
36    
37    oled.show() 
38    sleep_ms(500) 
39    isPoint = not isPoint

5. sh1106.py OLED driver library:

  1# Modified and copy some initializations from ssd1306
  2# to prevent inverted display and the breathing like
  3# effect on the display. I don't know the reason but it works
  4# Original from: https://github.com/robert-hh/SH1106/blob/master/sh1106.py
  5# 
  6# MicroPython SH1106 OLED driver, I2C and SPI interfaces 
  7# 
  8# The MIT License (MIT) 
  9# 
 10# Copyright (c) 2016 Radomir Dopieralski (@deshipu), 2017 Robert Hammelrath (@robert-hh) 
 11# 
 12# Permission is hereby granted, free of charge, to any person obtaining a copy 
 13# of this software and associated documentation files (the "Software"), to deal 
 14# in the Software without restriction, including without limitation the rights 
 15# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 16# copies of the Software, and to permit persons to whom the Software is 
 17# furnished to do so, subject to the following conditions: 
 18# 
 19# The above copyright notice and this permission notice shall be included in 
 20# all copies or substantial portions of the Software. 
 21# 
 22# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 23# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 24# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 25# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 26# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 27# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
 28# THE SOFTWARE. 
 29# 
 30# Sample code sections 
 31# ------------ SPI ------------------ 
 32# Pin Map SPI 
 33#   - 3v - xxxxxx   - Vcc 
 34#   - G  - xxxxxx   - Gnd 
 35#   - D7 - GPIO 13  - Din / MOSI fixed 
 36#   - D5 - GPIO 14  - Clk / Sck fixed 
 37#   - D8 - GPIO 4   - CS (optional, if the only connected device) 
 38#   - D2 - GPIO 5   - D/C 
 39#   - D1 - GPIO 2   - Res 
 40# 
 41# for CS, D/C and Res other ports may be chosen. 
 42# 
 43# from machine import Pin, SPI 
 44# import sh1106 
 45# spi = SPI(1, baudrate=1000000) 
 46# display = sh1106.SH1106_SPI(128, 64, spi, Pin(5), Pin(2), Pin(4)) 
 47# display.sleep(False) 
 48# display.fill(0) 
 49# display.text('Testing 1', 0, 0, 1) 
 50# display.show() 
 51# 
 52# --------------- I2C ------------------ 
 53# 
 54# Pin Map I2C 
 55#   - 3v - xxxxxx   - Vcc 
 56#   - G  - xxxxxx   - Gnd 
 57#   - D2 - GPIO 5   - SCK / SCL 
 58#   - D1 - GPIO 4   - DIN / SDA 
 59#   - D0 - GPIO 16  - Res 
 60#   - G  - xxxxxx     CS 
 61#   - G  - xxxxxx     D/C 
 62# 
 63# Pin's for I2C can be set almost arbitrary 
 64# 
 65# from machine import Pin, I2C 
 66# import sh1106 
 67# 
 68# i2c = I2C(scl=Pin(5), sda=Pin(4), freq=400000) 
 69# display = sh1106.SH1106_I2C(128, 64, i2c, Pin(16), 0x3c) 
 70# display.sleep(False) 
 71# display.fill(0) 
 72# display.text('Testing 1', 0, 0, 1) 
 73# display.show() 
 74
 75from micropython import const 
 76import utime as time 
 77import framebuf
 78
 79# Copy some definitions from ssd1306
 80# a few register definitions 
 81
 82_SET_CONTRAST        = const(0x81)  
 83_SET_SCAN_DIR        = const(0xc0) 
 84_SET_SEG_REMAP       = const(0xa0)
 85_SET_DISP            = const(0xae) 
 86_LOW_COLUMN_ADDRESS  = const(0x00) 
 87_HIGH_COLUMN_ADDRESS = const(0x10) 
 88_SET_PAGE_ADDRESS    = const(0xB0)
 89SET_CONTRAST        = const(0x81)
 90SET_ENTIRE_ON       = const(0xa4)
 91SET_NORM_INV        = const(0xa6)
 92SET_DISP            = const(0xae)
 93SET_MEM_ADDR        = const(0x20)
 94SET_COL_ADDR        = const(0x21)
 95SET_PAGE_ADDR       = const(0x22)
 96SET_DISP_START_LINE = const(0x40)
 97SET_SEG_REMAP       = const(0xa0)
 98SET_MUX_RATIO       = const(0xa8)
 99SET_COM_OUT_DIR     = const(0xc0)
100SET_DISP_OFFSET     = const(0xd3)
101SET_COM_PIN_CFG     = const(0xda)
102SET_DISP_CLK_DIV    = const(0xd5)
103SET_PRECHARGE       = const(0xd9)
104SET_VCOM_DESEL      = const(0xdb)
105SET_CHARGE_PUMP     = const(0x8d)
106
107class SH1106: 
108    def __init__(self, width, height, external_vcc): 
109        self.width = width 
110        self.height = height 
111        self.external_vcc = external_vcc 
112        self.pages = self.height // 8 
113        self.buffer = bytearray(self.pages * self.width) 
114        fb = framebuf.FrameBuffer(self.buffer, self.width, self.height, framebuf.MVLSB) 
115        self.framebuf = fb 
116# set shortcuts for the methods of framebuf 
117        self.fill = fb.fill 
118        self.fill_rect = fb.fill_rect 
119        self.hline = fb.hline 
120        self.vline = fb.vline 
121        self.line = fb.line 
122        self.rect = fb.rect 
123        self.pixel = fb.pixel 
124        self.scroll = fb.scroll 
125        self.text = fb.text 
126        self.blit = fb.blit
127        self.poweron()
128        self.init_display()
129        
130# Comment out and copy the init_display from ssd1306
131#     def init_display(self): 
132#         self.reset() 
133#         self.fill(0) 
134#         self.poweron() 
135#         self.show()
136    def init_display(self):
137        for cmd in (
138            SET_DISP | 0x00, # off
139            # address setting
140            SET_MEM_ADDR, 0x00, # horizontal
141            # resolution and layout
142            SET_DISP_START_LINE | 0x00,
143            SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
144            SET_MUX_RATIO, self.height - 1,
145            SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
146            SET_DISP_OFFSET, 0x00,
147            SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
148            # timing and driving scheme
149            SET_DISP_CLK_DIV, 0x80,
150            SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
151            SET_VCOM_DESEL, 0x30, # 0.83*Vcc
152            # display
153            SET_CONTRAST, 0xff, # maximum
154            SET_ENTIRE_ON, # output follows RAM contents
155            SET_NORM_INV, # not inverted
156            # charge pump
157            SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
158            SET_DISP | 0x01): # on
159            self.write_cmd(cmd)
160        self.fill(0)
161        self.show()
162
163    def poweroff(self): 
164        self.write_cmd(_SET_DISP | 0x00) 
165    def poweron(self): 
166        self.write_cmd(_SET_DISP | 0x01) 
167    def rotate(self, flag, update = True): 
168        if flag: 
169            self.write_cmd(_SET_SEG_REMAP | 0x01) # mirror display vertically 
170            self.write_cmd(_SET_SCAN_DIR | 0x08) # mirror display horizontically 
171        else: 
172            self.write_cmd(_SET_SEG_REMAP | 0x00) # 
173            self.write_cmd(_SET_SCAN_DIR | 0x00) # 
174        if update: 
175            self.show() 
176    def sleep(self, value): 
177        self.write_cmd(_SET_DISP | (not value)) 
178    def contrast(self, contrast): 
179        self.write_cmd(_SET_CONTRAST) 
180        self.write_cmd(contrast) 
181    def invert(self, invert): 
182        self.write_cmd(_SET_NORM_INV | (invert & 1)) 
183    def show(self): 
184        for page in range(self.height // 8): 
185            self.write_cmd(_SET_PAGE_ADDRESS | page) 
186            self.write_cmd(_LOW_COLUMN_ADDRESS | 2) 
187            self.write_cmd(_HIGH_COLUMN_ADDRESS | 0) 
188            self.write_data(self.buffer[ 
189                self.width * page:self.width * page + self.width 
190            ]) 
191    def reset(self, res): 
192        if res is not None: 
193            res(1) 
194            time.sleep_ms(1) 
195            res(0) 
196            time.sleep_ms(20) 
197            res(1) 
198            time.sleep_ms(20) 
199class SH1106_I2C(SH1106): 
200    def __init__(self, width, height, i2c, res=None, addr=0x3c, external_vcc=False): 
201        self.i2c = i2c 
202        self.addr = addr 
203        self.res = res 
204        self.temp = bytearray(2) 
205        if hasattr(self.i2c, "start"): 
206            self.write_data = self.sw_write_data 
207        else: 
208            self.write_data = self.hw_write_data 
209        if res is not None: 
210            res.init(res.OUT, value=1) 
211        super().__init__(width, height, external_vcc) 
212    def write_cmd(self, cmd): 
213        self.temp[0] = 0x80 # Co=1, D/C#=0 
214        self.temp[1] = cmd 
215        self.i2c.writeto(self.addr, self.temp) 
216    def hw_write_data(self, buf): 
217        self.i2c.writeto(self.addr, b'x40'+buf) 
218    def sw_write_data(self, buf): 
219        self.temp[0] = self.addr << 1 
220        self.temp[1] = 0x40 # Co=0, D/C#=1 
221        self.i2c.start() 
222        self.i2c.write(self.temp) 
223        self.i2c.write(buf) 
224        self.i2c.stop() 
225    def reset(self): 
226        super().reset(self.res) 
227class SH1106_SPI(SH1106): 
228    def __init__(self, width, height, spi, dc, res=None, cs=None, external_vcc=False): 
229        self.rate = 10 * 1000 * 1000 
230        dc.init(dc.OUT, value=0) 
231        if res is not None: 
232            res.init(res.OUT, value=0) 
233        if cs is not None: 
234            cs.init(cs.OUT, value=1) 
235        self.spi = spi 
236        self.dc = dc 
237        self.res = res 
238        self.cs = cs 
239        super().__init__(width, height, external_vcc) 
240    def write_cmd(self, cmd): 
241        self.spi.init(baudrate=self.rate, polarity=0, phase=0) 
242        if self.cs is not None: 
243            self.cs(1) 
244            self.dc(0) 
245            self.cs(0) 
246            self.spi.write(bytearray([cmd])) 
247            self.cs(1) 
248        else: 
249            self.dc(0) 
250            self.spi.write(bytearray([cmd])) 
251    def write_data(self, buf): 
252        self.spi.init(baudrate=self.rate, polarity=0, phase=0) 
253        if self.cs is not None: 
254            self.cs(1) 
255            self.dc(1) 
256            self.cs(0) 
257            self.spi.write(buf) 
258            self.cs(1) 
259        else: 
260            self.dc(1) 
261            self.spi.write(buf) 
262    def reset(self): 
263        super().reset(self.res)

6. Custom font writer utility, writer minimal.py:

 1# writer_minimal.py Implements the Writer class.
 2# Minimal version for SSD1306
 3# V0.22 Peter Hinch 3rd Jan 2018: Supports new SSD1306 driver.
 4
 5# The MIT License (MIT)
 6#
 7# Copyright (c) 2016 Peter Hinch
 8#
 9# Permission is hereby granted, free of charge, to any person obtaining a copy
10# of this software and associated documentation files (the "Software"), to deal
11# in the Software without restriction, including without limitation the rights
12# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13# copies of the Software, and to permit persons to whom the Software is
14# furnished to do so, subject to the following conditions:
15#
16# The above copyright notice and this permission notice shall be included in
17# all copies or substantial portions of the Software.
18#
19# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25# THE SOFTWARE.
26
27# A Writer supports rendering text to a Display instance in a given font.
28# Multiple Writer instances may be created, each rendering a font to the
29# same Display object.
30
31import framebuf
32
33class Writer():
34    text_row = 0        # attributes common to all Writer instances
35    text_col = 0
36    row_clip = False    # Clip or scroll when screen full
37    col_clip = False    # Clip or new line when row is full
38
39    @classmethod
40    def set_textpos(cls, row, col):
41        cls.text_row = row
42        cls.text_col = col
43
44    @classmethod
45    def set_clip(cls, row_clip, col_clip):
46        cls.row_clip = row_clip
47        cls.col_clip = col_clip
48
49    def __init__(self, device, font, verbose=True):
50        self.device = device
51        self.font = font
52        # Allow to work with any font mapping
53        if font.hmap():
54            self.map = framebuf.MONO_HMSB if font.reverse() else framebuf.MONO_HLSB
55        else:
56            raise ValueError('Font must be horizontally mapped.')
57        if verbose:
58            print('Orientation: {} Reversal: {}'.format('horiz' if font.hmap() else 'vert', font.reverse()))
59        self.screenwidth = device.width  # In pixels
60        self.screenheight = device.height
61
62    def _newline(self):
63        height = self.font.height()
64        Writer.text_row += height
65        Writer.text_col = 0
66        margin = self.screenheight - (Writer.text_row + height)
67        if margin < 0:
68            if not Writer.row_clip:
69                self.device.scroll(0, margin)
70                Writer.text_row += margin
71
72    def printstring(self, string):
73        for char in string:
74            self._printchar(char)
75
76    # Method using blitting. Efficient rendering for monochrome displays.
77    # Tested on SSD1306. Invert is for black-on-white rendering.
78    def _printchar(self, char, invert=False):
79        if char == 'n':
80            self._newline()
81            return
82        glyph, char_height, char_width = self.font.get_ch(char)
83        if Writer.text_row + char_height > self.screenheight:
84            if Writer.row_clip:
85                return
86            self._newline()
87        if Writer.text_col + char_width > self.screenwidth:
88            if Writer.col_clip:
89                return
90            else:
91                self._newline()
92        buf = bytearray(glyph)
93        if invert:
94            for i, v in enumerate(buf):
95                buf[i] = 0xFF & ~ v
96        fbc = framebuf.FrameBuffer(buf, char_width, char_height, self.map)
97        self.device.blit(fbc, Writer.text_col, Writer.text_row)
98        Writer.text_col += char_width

7. Custom font, freesans20.py:

  1# Code generated by font-to-py.py.
  2# Font: FreeSans.ttf
  3
  4def height():
  5    return 20
  6
  7def max_width():
  8    return 20
  9
 10def hmap():
 11    return True
 12
 13def reverse():
 14    return False
 15
 16def monospaced():
 17    return False
 18
 19def min_ch():
 20    return 32
 21
 22def max_ch():
 23    return 126
 24
 25_font =
 26b'x0bx00x00x00x3cx00x7ex00xc7x00xc3x00x03x00x03x00'
 27b'x06x00x0cx00x08x00x18x00x18x00x00x00x00x00x18x00'
 28b'x18x00x00x00x00x00x00x00x00x00x05x00x00x00x00x00'
 29b'x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00'
 30b'x07x00x00xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0x00x00'
 31b'xc0xc0x00x00x00x00x07x00x00x00xd8xd8xd8xd8x90x00'
 32b'x00x00x00x00x00x00x00x00x00x00x00x00x0bx00x00x00'
 33b'x00x00x0cxc0x08x80x08x80x7fxe0x7fxe0x19x80x11x00'
 34b'x11x00xffxc0xffxc0x33x00x33x00x22x00x22x00x00x00'
 35b'x00x00x00x00x00x00x0bx00x08x00x3ex00x7fx80xe9xc0'
 36b'xc8xc0xc8xc0xc8x00xe8x00x7cx00x1fx80x09xc0x08xc0'
 37b'xc8xc0xe9xc0x7fx80x3ex00x08x00x00x00x00x00x00x00'
 38b'x12x00x00x00x00x00x00x00x38x10x00x7cx10x00xc6x20'
 39b'x00xc6x20x00xc6x40x00x7cxc0x00x38x80x00x01x1ex00'
 40b'x01x3fx00x02x73x80x02x61x80x04x73x80x04x3fx00x08'
 41b'x1ex00x00x00x00x00x00x00x00x00x00x00x00x00x0dx00'
 42b'x00x00x00x00x0ex00x1fx00x31x80x31x80x31x80x1fx00'
 43b'x1cx00x76x60xe3x60xc1xc0xc0xc0xe1xc0x7fx60x3ex30'
 44b'x00x00x00x00x00x00x00x00x04x00x00x00xc0xc0xc0xc0'
 45b'x80x00x00x00x00x00x00x00x00x00x00x00x00x00x07x00'
 46b'x00x10x10x20x20x60x40xc0xc0xc0xc0xc0xc0xc0x40x60'
 47b'x20x30x10x18x07x00x00x40x40x20x20x30x10x18x18x18'
 48b'x18x18x18x18x10x30x20x60x40xc0x08x00x00x20x20xf8'
 49b'x20x50x50x00x00x00x00x00x00x00x00x00x00x00x00x00'
 50b'x0cx00x00x00x00x00x00x00x00x00x00x00x00x00x00x00'
 51b'x18x00x18x00x18x00xffx00xffx00x18x00x18x00x18x00'
 52b'x18x00x00x00x00x00x00x00x00x00x06x00x00x00x00x00'
 53b'x00x00x00x00x00x00x00x00x00x00xc0xc0x40x40x80x00'
 54b'x07x00x00x00x00x00x00x00x00x00x00xf8xf8x00x00x00'
 55b'x00x00x00x00x00x00x05x00x00x00x00x00x00x00x00x00'
 56b'x00x00x00x00x00x00xc0xc0x00x00x00x00x06x00x00x04'
 57b'x0cx08x08x18x10x10x30x20x20x60x40x40xc0x80x00x00'
 58b'x00x00x0bx00x00x00x00x00x3ex00x7fx00x63x00xe3x80'
 59b'xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80xe3x80x63x00'
 60b'x7fx00x3ex00x00x00x00x00x00x00x00x00x0bx00x00x00'
 61b'x00x00x10x00x30x00xf0x00xf0x00x30x00x30x00x30x00'
 62b'x30x00x30x00x30x00x30x00x30x00x30x00x30x00x00x00'
 63b'x00x00x00x00x00x00x0bx00x00x00x00x00x3ex00x7fx00'
 64b'xe3x80xc1x80x01x80x01x80x03x00x0ex00x1cx00x30x00'
 65b'x60x00xc0x00xffx80xffx80x00x00x00x00x00x00x00x00'
 66b'x0bx00x00x00x00x00x3ex00x7fx00xe3x80xc1x80x01x80'
 67b'x0fx00x0fx00x03x80x01x80x01x80xc1x80xe3x80x7fx00'
 68b'x3ex00x00x00x00x00x00x00x00x00x0bx00x00x00x00x00'
 69b'x06x00x06x00x0ex00x1ex00x16x00x26x00x46x00x46x00'
 70b'x86x00xffx00xffx00x06x00x06x00x06x00x00x00x00x00'
 71b'x00x00x00x00x0bx00x00x00x00x00x7fx00x7fx00x60x00'
 72b'x60x00xdex00xffx00xe3x80x01x80x01x80x01x80x01x80'
 73b'xc3x00x7fx00x3ex00x00x00x00x00x00x00x00x00x0bx00'
 74b'x00x00x00x00x1ex00x3fx00x63x00x61x80xc0x00xdex00'
 75b'xffx00xe3x80xc1x80xc1x80xc1x80x63x80x7fx00x3ex00'
 76b'x00x00x00x00x00x00x00x00x0bx00x00x00x00x00xffx80'
 77b'xffx80x01x00x03x00x02x00x06x00x04x00x0cx00x08x00'
 78b'x18x00x18x00x10x00x30x00x30x00x00x00x00x00x00x00'
 79b'x00x00x0bx00x00x00x00x00x1cx00x3ex00x63x00x63x00'
 80b'x63x00x3ex00x3ex00x63x00xc1x80xc1x80xc1x80x63x00'
 81b'x7fx00x1cx00x00x00x00x00x00x00x00x00x0bx00x00x00'
 82b'x00x00x3ex00x7fx00xe3x00xc1x80xc1x80xc1x80xe3x80'
 83b'x7fx80x3dx80x01x80x03x00xe3x00x7ex00x3cx00x00x00'
 84b'x00x00x00x00x00x00x05x00x00x00x00x00x00xc0xc0x00'
 85b'x00x00x00x00x00x00xc0xc0x00x00x00x00x05x00x00x00'
 86b'x00x00x00x00xc0xc0x00x00x00x00x00x00xc0xc0x40x40'
 87b'x80x00x0cx00x00x00x00x00x00x00x00x00x00x00x00x00'
 88b'x00x40x01xc0x07x00x3cx00xe0x00xe0x00x78x00x0fx00'
 89b'x03xc0x00x40x00x00x00x00x00x00x00x00x0cx00x00x00'
 90b'x00x00x00x00x00x00x00x00x00x00x00x00x00x00xffxc0'
 91b'xffxc0x00x00x00x00xffxc0xffxc0x00x00x00x00x00x00'
 92b'x00x00x00x00x00x00x0cx00x00x00x00x00x00x00x00x00'
 93b'x00x00x00x00x00x00xe0x00x78x00x0ex00x03xc0x01xc0'
 94b'x07x00x3cx00xf0x00x80x00x00x00x00x00x00x00x00x00'
 95b'x0bx00x00x00x3cx00x7ex00xc7x00xc3x00x03x00x03x00'
 96b'x06x00x0cx00x08x00x18x00x18x00x00x00x00x00x18x00'
 97b'x18x00x00x00x00x00x00x00x00x00x14x00x00x00x00x03'
 98b'xf0x00x0fxfcx00x1ex0fx00x38x03x80x71xe1x80x63xe9'
 99b'xc0x67x18xc0xcex18xc0xccx18xc0xccx10xc0xccx31x80'
100b'xcex73x80x67xffx00x63x9ex00x30x00x00x3cx00x00x0f'
101b'xf8x00x03xf0x00x00x00x00x0dx00x00x00x07x00x07x00'
102b'x07x80x0dx80x0dx80x08xc0x18xc0x18xc0x10x60x3fxe0'
103b'x3fxe0x30x30x60x30x60x38xc0x18x00x00x00x00x00x00'
104b'x00x00x0dx00x00x00xffx00xffx80xc1xc0xc0xc0xc0xc0'
105b'xc1xc0xffx00xffx80xc0xc0xc0x60xc0x60xc0x60xc0xe0'
106b'xffxc0xffx80x00x00x00x00x00x00x00x00x0ex00x00x00'
107b'x0fx80x3fxe0x70x60x60x30xe0x00xc0x00xc0x00xc0x00'
108b'xc0x00xc0x00xe0x30x60x70x70x60x3fxe0x0fx80x00x00'
109b'x00x00x00x00x00x00x0ex00x00x00xffx00xffx80xc1xc0'
110b'xc0xc0xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60'
111b'xc0xc0xc1xc0xffx80xffx00x00x00x00x00x00x00x00x00'
112b'x0dx00x00x00xffxc0xffxc0xc0x00xc0x00xc0x00xc0x00'
113b'xffx80xffx80xc0x00xc0x00xc0x00xc0x00xc0x00xffxc0'
114b'xffxc0x00x00x00x00x00x00x00x00x0cx00x00x00xffx80'
115b'xffx80xc0x00xc0x00xc0x00xc0x00xffx00xffx00xc0x00'
116b'xc0x00xc0x00xc0x00xc0x00xc0x00xc0x00x00x00x00x00'
117b'x00x00x00x00x0fx00x00x00x0fxc0x3fxf0x38x30x60x18'
118b'x60x00xc0x00xc0x00xc1xf8xc1xf8xc0x18xe0x18x60x38'
119b'x78x78x3fxd8x0fx88x00x00x00x00x00x00x00x00x0ex00'
120b'x00x00xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60xffxe0'
121b'xffxe0xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60'
122b'x00x00x00x00x00x00x00x00x06x00x00xc0xc0xc0xc0xc0'
123b'xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0x00x00x00x00x0bx00'
124b'x00x00x03x00x03x00x03x00x03x00x03x00x03x00x03x00'
125b'x03x00x03x00x03x00xc3x00xc3x00xe7x00x7ex00x3cx00'
126b'x00x00x00x00x00x00x00x00x0dx00x00x00xc0x60xc0xc0'
127b'xc1x80xc3x00xc6x00xccx00xdcx00xf6x00xe6x00xc3x00'
128b'xc1x80xc1x80xc0xc0xc0x60xc0x60x00x00x00x00x00x00'
129b'x00x00x0bx00x00x00xc0x00xc0x00xc0x00xc0x00xc0x00'
130b'xc0x00xc0x00xc0x00xc0x00xc0x00xc0x00xc0x00xc0x00'
131b'xffx80xffx80x00x00x00x00x00x00x00x00x11x00x00x00'
132b'x00xe0x1cx00xe0x1cx00xf0x3cx00xf0x3cx00xd0x2cx00'
133b'xd8x6cx00xd8x6cx00xc8x4cx00xccxccx00xccxccx00xc4'
134b'x8cx00xc6x8cx00xc7x8cx00xc3x0cx00xc3x0cx00x00x00'
135b'x00x00x00x00x00x00x00x00x00x00x0fx00x00x00xe0x60'
136b'xe0x60xf0x60xf0x60xd8x60xd8x60xccx60xc4x60xc6x60'
137b'xc2x60xc3x60xc1xe0xc1xe0xc0xe0xc0xe0x00x00x00x00'
138b'x00x00x00x00x10x00x00x00x0fxc0x1fxe0x38x70x60x18'
139b'x60x1cxc0x0cxc0x0cxc0x0cxc0x0cxc0x0cx60x1cx60x18'
140b'x38x70x1fxe0x0fxc0x00x00x00x00x00x00x00x00x0dx00'
141b'x00x00xffx00xffx80xc1xc0xc0xc0xc0xc0xc0xc0xc1xc0'
142b'xffx80xffx00xc0x00xc0x00xc0x00xc0x00xc0x00xc0x00'
143b'x00x00x00x00x00x00x00x00x10x00x00x00x0fxc0x1fxe0'
144b'x38x70x60x18x60x1cxc0x0cxc0x0cxc0x0cxc0x0cxc0x0c'
145b'x60x18x60xd8x38x70x1fxf8x0fx98x00x08x00x00x00x00'
146b'x00x00x0ex00x00x00xffx80xffxc0xc0xe0xc0x60xc0x60'
147b'xc0x60xc0xc0xffx80xffxc0xc0xe0xc0x60xc0x60xc0x60'
148b'xc0x60xc0x70x00x00x00x00x00x00x00x00x0dx00x00x00'
149b'x1fx80x7fxe0xe0x70xc0x30xc0x00xe0x00x78x00x3fx80'
150b'x03xe0x00x70xc0x30xc0x30x70x60x7fxe0x1fx80x00x00'
151b'x00x00x00x00x00x00x0dx00x00x00xffxc0xffxc0x0cx00'
152b'x0cx00x0cx00x0cx00x0cx00x0cx00x0cx00x0cx00x0cx00'
153b'x0cx00x0cx00x0cx00x0cx00x00x00x00x00x00x00x00x00'
154b'x0ex00x00x00xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60'
155b'xc0x60xc0x60xc0x60xc0x60xc0x60xc0x60x60xc0x7fxc0'
156b'x1fx00x00x00x00x00x00x00x00x00x0dx00x00x00xc0x30'
157b'x60x30x60x30x20x20x30x60x30x60x10x40x18xc0x18xc0'
158b'x08x80x0dx80x0dx80x07x00x07x00x07x00x00x00x00x00'
159b'x00x00x00x00x13x00x00x00x00xc0xc0xc0x60xe0xc0x60'
160b'xe0xc0x61xe0xc0x61xb1x80x31xb1x80x31xb1x80x33x11'
161b'x80x33x19x00x13x1bx00x1fx1bx00x1ex0bx00x1ex0ex00'
162b'x0ex0ex00x0cx06x00x00x00x00x00x00x00x00x00x00x00'
163b'x00x00x0dx00x00x00x60x30x30x70x30x60x18xc0x0cxc0'
164b'x0dx80x07x00x07x00x07x00x0dx80x18xc0x18xe0x30x60'
165b'x70x30x60x38x00x00x00x00x00x00x00x00x0ex00x00x00'
166b'x60x18x70x38x30x30x18x60x18x60x0cxc0x0fxc0x07x80'
167b'x03x00x03x00x03x00x03x00x03x00x03x00x03x00x00x00'
168b'x00x00x00x00x00x00x0cx00x00x00xffxe0xffxe0x00xc0'
169b'x01x80x03x80x03x00x06x00x0cx00x1cx00x38x00x30x00'
170b'x60x00xc0x00xffxe0xffxe0x00x00x00x00x00x00x00x00'
171b'x06x00x00xe0xe0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0'
172b'xc0xc0xc0xc0xe0xe0x06x00x00x80xc0x40x40x60x20x20'
173b'x30x10x10x18x08x08x0cx04x00x00x00x00x06x00x00xe0'
174b'xe0x60x60x60x60x60x60x60x60x60x60x60x60x60x60x60'
175b'xe0xe0x09x00x00x00x00x00x18x00x38x00x28x00x2cx00'
176b'x64x00x46x00xc2x00x82x00x00x00x00x00x00x00x00x00'
177b'x00x00x00x00x00x00x00x00x00x00x00x00x0cx00x00x00'
178b'x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00'
179b'x00x00x00x00x00x00x00x00x00x00x00x00x00x00xffxf0'
180b'x00x00x00x00x00x00x05x00x00xc0x60x30x00x00x00x00'
181b'x00x00x00x00x00x00x00x00x00x00x00x00x0bx00x00x00'
182b'x00x00x00x00x00x00x00x00x3ex00xffx80xc1x80x01x80'
183b'x01x80x3fx80xf1x80xc1x80xc3x80xffxc0x78xc0x00x00'
184b'x00x00x00x00x00x00x0bx00x00x00xc0x00xc0x00xc0x00'
185b'xc0x00xdfx00xffx80xe1x80xc0xc0xc0xc0xc0xc0xc0xc0'
186b'xc0xc0xe1x80xffx80xdex00x00x00x00x00x00x00x00x00'
187b'x0ax00x00x00x00x00x00x00x00x00x00x00x1ex00x7fx00'
188b'x61x80xc0x00xc0x00xc0x00xc0x00xc1x80x63x80x7fx00'
189b'x3ex00x00x00x00x00x00x00x00x00x0bx00x00x00x01x80'
190b'x01x80x01x80x01x80x3dx80x7fx80x63x80xc1x80xc1x80'
191b'xc1x80xc1x80xc1x80x63x80x7fx80x3dx80x00x00x00x00'
192b'x00x00x00x00x0bx00x00x00x00x00x00x00x00x00x00x00'
193b'x3ex00x7fx00x63x00xc1x80xffx80xffx80xc0x00xc0x00'
194b'x63x80x7fx00x3ex00x00x00x00x00x00x00x00x00x06x00'
195b'x00x30x70x60x60xf0xf0x60x60x60x60x60x60x60x60x60'
196b'x00x00x00x00x0bx00x00x00x00x00x00x00x00x00x00x00'
197b'x3dx80x7fx80x63x80xc1x80xc1x80xc1x80xc1x80xc1x80'
198b'x63x80x7fx80x3dx80x01x80xc3x80x7fx00x3ex00x0bx00'
199b'x00x00xc0x00xc0x00xc0x00xc0x00xdfx00xdfx80xe3x80'
200b'xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80'
201b'x00x00x00x00x00x00x00x00x04x00x00xc0xc0x00x00xc0'
202b'xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0x00x00x00x00x05x00'
203b'x00x30x30x00x00x30x30x30x30x30x30x30x30x30x30x30'
204b'x30x30xf0xe0x0ax00x00x00xc0x00xc0x00xc0x00xc0x00'
205b'xc3x00xc6x00xccx00xd8x00xf8x00xecx00xcex00xc6x00'
206b'xc3x00xc3x00xc1x80x00x00x00x00x00x00x00x00x04x00'
207b'x00xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0'
208b'x00x00x00x00x10x00x00x00x00x00x00x00x00x00x00x00'
209b'xdex78xfexfcxe3x8cxc3x0cxc3x0cxc3x0cxc3x0cxc3x0c'
210b'xc3x0cxc3x0cxc3x0cx00x00x00x00x00x00x00x00x0bx00'
211b'x00x00x00x00x00x00x00x00x00x00xcfx00xdfx80xe3x80'
212b'xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80xc1x80'
213b'x00x00x00x00x00x00x00x00x0bx00x00x00x00x00x00x00'
214b'x00x00x00x00x3ex00x7fx00x63x00xc1x80xc1x80xc1x80'
215b'xc1x80xc1x80x63x00x7fx00x3ex00x00x00x00x00x00x00'
216b'x00x00x0bx00x00x00x00x00x00x00x00x00x00x00xdex00'
217b'xffx80xe1x80xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xe1x80'
218b'xffx80xdex00xc0x00xc0x00xc0x00x00x00x0bx00x00x00'
219b'x00x00x00x00x00x00x00x00x3dx80x7fx80x63x80xc1x80'
220b'xc1x80xc1x80xc1x80xc1x80x63x80x7fx80x3dx80x01x80'
221b'x01x80x01x80x00x00x07x00x00x00x00x00x00xd8xf8xe0'
222b'xc0xc0xc0xc0xc0xc0xc0xc0x00x00x00x00x0ax00x00x00'
223b'x00x00x00x00x00x00x00x00x3cx00x7fx00xc3x00xc0x00'
224b'xf0x00x7ex00x0fx00x03x00xc3x00xfex00x7cx00x00x00'
225b'x00x00x00x00x00x00x06x00x00x00x00x60x60xf0xf0x60'
226b'x60x60x60x60x60x60x70x70x00x00x00x00x0bx00x00x00'
227b'x00x00x00x00x00x00x00x00xc1x80xc1x80xc1x80xc1x80'
228b'xc1x80xc1x80xc1x80xc1x80xe3x80xfdx80x79x80x00x00'
229b'x00x00x00x00x00x00x0ax00x00x00x00x00x00x00x00x00'
230b'x00x00xc0xc0x61x80x61x80x61x00x23x00x33x00x32x00'
231b'x16x00x1ex00x1cx00x0cx00x00x00x00x00x00x00x00x00'
232b'x0ex00x00x00x00x00x00x00x00x00x00x00xc3x0cxc3x8c'
233b'x63x8cx67x88x66x98x24xd8x34xd0x3cxd0x3cx70x18x70'
234b'x18x60x00x00x00x00x00x00x00x00x0ax00x00x00x00x00'
235b'x00x00x00x00x00x00x61x80x63x00x33x00x1ex00x1cx00'
236b'x0cx00x1cx00x16x00x33x00x63x00x41x80x00x00x00x00'
237b'x00x00x00x00x0ax00x00x00x00x00x00x00x00x00x00x00'
238b'xc0x80x41x80x61x80x61x00x23x00x33x00x32x00x16x00'
239b'x1cx00x1cx00x0cx00x08x00x18x00x78x00x70x00x0ax00'
240b'x00x00x00x00x00x00x00x00x00x00xffx00xffx00x06x00'
241b'x06x00x0cx00x18x00x30x00x60x00xc0x00xffx00xffx00'
242b'x00x00x00x00x00x00x00x00x07x00x00x18x38x30x30x30'
243b'x30x30x30x70xc0x70x30x30x30x30x30x30x38x18x05x00'
244b'x00xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0xc0'
245b'xc0xc0xc0xc0x07x00x00xc0xe0x60x60x60x60x60x60x70'
246b'x18x70x60x60x60x60x60x60xe0xc0x0ax00x00x00x00x00'
247b'x00x00x00x00x00x00x00x00x00x00x60x00xf1x00x9fx00'
248b'x06x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00'
249b'x00x00x00x00'
250
251_index =
252b'x00x00x2ax00x2ax00x40x00x40x00x56x00x56x00x6cx00'
253b'x6cx00x96x00x96x00xc0x00xc0x00xfex00xfex00x28x01'
254b'x28x01x3ex01x3ex01x54x01x54x01x6ax01x6ax01x80x01'
255b'x80x01xaax01xaax01xc0x01xc0x01xd6x01xd6x01xecx01'
256b'xecx01x02x02x02x02x2cx02x2cx02x56x02x56x02x80x02'
257b'x80x02xaax02xaax02xd4x02xd4x02xfex02xfex02x28x03'
258b'x28x03x52x03x52x03x7cx03x7cx03xa6x03xa6x03xbcx03'
259b'xbcx03xd2x03xd2x03xfcx03xfcx03x26x04x26x04x50x04'
260b'x50x04x7ax04x7ax04xb8x04xb8x04xe2x04xe2x04x0cx05'
261b'x0cx05x36x05x36x05x60x05x60x05x8ax05x8ax05xb4x05'
262b'xb4x05xdex05xdex05x08x06x08x06x1ex06x1ex06x48x06'
263b'x48x06x72x06x72x06x9cx06x9cx06xdax06xdax06x04x07'
264b'x04x07x2ex07x2ex07x58x07x58x07x82x07x82x07xacx07'
265b'xacx07xd6x07xd6x07x00x08x00x08x2ax08x2ax08x54x08'
266b'x54x08x92x08x92x08xbcx08xbcx08xe6x08xe6x08x10x09'
267b'x10x09x26x09x26x09x3cx09x3cx09x52x09x52x09x7cx09'
268b'x7cx09xa6x09xa6x09xbcx09xbcx09xe6x09xe6x09x10x0a'
269b'x10x0ax3ax0ax3ax0ax64x0ax64x0ax8ex0ax8ex0axa4x0a'
270b'xa4x0axcex0axcex0axf8x0axf8x0ax0ex0bx0ex0bx24x0b'
271b'x24x0bx4ex0bx4ex0bx64x0bx64x0bx8ex0bx8ex0bxb8x0b'
272b'xb8x0bxe2x0bxe2x0bx0cx0cx0cx0cx36x0cx36x0cx4cx0c'
273b'x4cx0cx76x0cx76x0cx8cx0cx8cx0cxb6x0cxb6x0cxe0x0c'
274b'xe0x0cx0ax0dx0ax0dx34x0dx34x0dx5ex0dx5ex0dx88x0d'
275b'x88x0dx9ex0dx9ex0dxb4x0dxb4x0dxcax0dxcax0dxf4x0d'
276
277_mvfont = memoryview(_font)
278
279def get_ch(ch):
280    ordch = ord(ch)
281    ordch = ordch + 1 if ordch >= 32 and ordch <= 126 else 32
282    idx_offs = 4 * (ordch - 32)
283    offset = int.from_bytes(_index[idx_offs : idx_offs + 2], 'little')
284    next_offs = int.from_bytes(_index[idx_offs + 2 : idx_offs + 4], 'little')
285    width = int.from_bytes(_font[offset:offset + 2], 'little')
286    return _mvfont[offset + 2:next_offs], 20, width

References And Credits

  1. SH106 by Robert Hammelrath and Radomir Dopieralski: https://github.com/robert-hh/SH1106/blob/master/sh1106.py

  2. Custom font library by Peter Hinch: https://github.com/peterhinch/micropython-font-to-py

  3. Purchase a copy of the Gorillacell ESP32 kit: gorillacell.kr



Posts in this series



No comments yet!

GitHub-flavored Markdown & a sane subset of HTML is supported.