RP2040 MCU Board with 1.28inch Round LCD
Jump to navigation
Jump to search
RP2040 Board with LCD
https://www.waveshare.com/rp2040-lcd-1.28.htm
https://www.waveshare.com/wiki/RP2040-LCD-1.28
Firmware with Display Driver: the regular micropython formware should work
here is a firmware with a build in driver
Display example
1 """
2 lines.py
3
4 Draws lines and rectangles in random colors at random locations on the
5 display.
6
7 """
8 import random
9 from machine import Pin, SPI
10 import gc9a01py as gc9a01
11
12
13 def main():
14 spi = SPI(1, baudrate=60000000, sck=Pin(10), mosi=Pin(11))
15 tft = gc9a01.GC9A01(
16 spi,
17 dc=Pin(8, Pin.OUT),
18 cs=Pin(9, Pin.OUT),
19 reset=Pin(12, Pin.OUT),
20 backlight=Pin(25, Pin.OUT),
21 rotation=0)
22
23 tft.fill(gc9a01.WHITE)
24
25 while True:
26 tft.line(
27 random.randint(0, tft.width),
28 random.randint(0, tft.height),
29 random.randint(0, tft.width),
30 random.randint(0, tft.height),
31 gc9a01.color565(
32 random.getrandbits(8),
33 random.getrandbits(8),
34 random.getrandbits(8)
35 )
36 )
37
38 width = random.randint(0, tft.width // 2)
39 height = random.randint(0, tft.height // 2)
40 col = random.randint(0, tft.width - width)
41 row = random.randint(0, tft.height - height)
42 tft.fill_rect(
43 col,
44 row,
45 width,
46 height,
47 gc9a01.color565(
48 random.getrandbits(8),
49 random.getrandbits(8),
50 random.getrandbits(8)
51 )
52 )
53
54
55 main()
Display Driver
downloaded from: https://github.com/russhughes/gc9a01py/tree/main
Filename: gc9a01py.py
1 """
2 Copyright (c) 2020, 2021 Russ Hughes
3
4 This file incorporates work covered by the following copyright and
5 permission notice and is licensed under the same terms:
6
7 The MIT License (MIT)
8
9 Copyright (c) 2019 Ivan Belokobylskiy
10
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 THE SOFTWARE.
28
29
30 GC9A01 Display driver in MicroPython based on devbis st7789py_mpy module from
31 https://github.com/devbis/st7789py_mpy modified to drive 240x240 pixel GC9A01
32 displays.
33
34 The driver supports display rotation, mirroring, scrolling and drawing text
35 using 8 and 16 bit wide bitmap fonts with heights that are multiples of 8.
36 Included are 12 bitmap fonts derived from classic pc text mode fonts and a
37 couple of example programs.
38
39 This is a work in progress. Documentation can be found at
40 https://penfold.owt.com/gc9a01py/.
41
42 If you are looking for a faster driver with additional features, check out the
43 C version of the driver at https://github.com/russhughes/gc9a01_mpy
44
45 """
46
47 # pylint: disable=invalid-name,import-error
48
49 import time
50 from micropython import const
51 import ustruct as struct
52
53 # commands
54 GC9A01_SWRESET = const(0x01)
55 GC9A01_SLPIN = const(0x10)
56 GC9A01_SLPOUT = const(0x11)
57 GC9A01_INVOFF = const(0x20)
58 GC9A01_INVON = const(0x21)
59 GC9A01_DISPOFF = const(0x28)
60 GC9A01_DISPON = const(0x29)
61 GC9A01_CASET = const(0x2A)
62 GC9A01_RASET = const(0x2B)
63 GC9A01_RAMWR = const(0x2C)
64 GC9A01_VSCRDEF = const(0x33)
65 GC9A01_COLMOD = const(0x3A)
66 GC9A01_MADCTL = const(0x36)
67 GC9A01_VSCSAD = const(0x37)
68
69 # Color definitions
70 BLACK = const(0x0000)
71 BLUE = const(0x001F)
72 RED = const(0xF800)
73 GREEN = const(0x07E0)
74 CYAN = const(0x07FF)
75 MAGENTA = const(0xF81F)
76 YELLOW = const(0xFFE0)
77 WHITE = const(0xFFFF)
78
79 _ENCODE_PIXEL = ">H"
80 _ENCODE_POS = ">HH"
81 _DECODE_PIXEL = ">BBB"
82
83 _BUFFER_SIZE = const(256)
84
85 _BIT7 = const(0x80)
86 _BIT6 = const(0x40)
87 _BIT5 = const(0x20)
88 _BIT4 = const(0x10)
89 _BIT3 = const(0x08)
90 _BIT2 = const(0x04)
91 _BIT1 = const(0x02)
92 _BIT0 = const(0x01)
93
94 ROTATIONS = [
95 0x48, # 0 - PORTRAIT
96 0x28, # 1 - LANDSCAPE
97 0x88, # 2 - INVERTED_PORTRAIT
98 0xe8, # 3 - INVERTED_LANDSCAPE
99 0x08, # 4 - PORTRAIT_MIRRORED
100 0x68, # 5 - LANDSCAPE_MIRRORED
101 0xc8, # 6 - INVERTED_PORTRAIT_MIRRORED
102 0xa8] # 7 - INVERTED_LANDSCAPE_MIRRORED]
103
104
105 def color565(red, green=0, blue=0):
106 """
107 Convert red, green and blue values (0-255) into a 16-bit 565 encoded color.
108 """
109 try:
110 red, green, blue = red # see if the first var is a tuple/list
111 except TypeError:
112 pass
113 return (red & 0xf8) << 8 | (green & 0xfc) << 3 | blue >> 3
114
115
116 def _encode_pos(x, y):
117 """Encode a postion into bytes."""
118 return struct.pack(_ENCODE_POS, x, y)
119
120
121 def _encode_pixel(color):
122 """Encode a pixel color into bytes."""
123 return struct.pack(_ENCODE_PIXEL, color)
124
125
126 class GC9A01():
127 """
128 GC9A01 driver class
129
130 Args:
131 spi (spi): spi object (Required)
132 dc (pin): dc pin (Required)
133 cs (pin): cs pin {optional}
134 reset (pin): reset pin
135 backlight(pin): backlight pin
136 rotation (int): display rotation
137 """
138
139 def __init__(
140 self,
141 spi=None,
142 dc=None,
143 cs=None,
144 reset=None,
145 backlight=None,
146 rotation=0):
147 """
148 Initialize display.
149 """
150 if spi is None:
151 raise ValueError("SPI object is required.")
152
153 if dc is None:
154 raise ValueError("dc pin is required.")
155
156 self.width = 240
157 self.height = 240
158 self.spi = spi
159 self.reset = reset
160 self.dc = dc
161 self.cs = cs
162 self.backlight = backlight
163 self._rotation = rotation % 8
164
165 self.hard_reset()
166 time.sleep_ms(100)
167
168 self._write(0xEF)
169 self._write(0xEB, b'\x14')
170 self._write(0xFE)
171 self._write(0xEF)
172 self._write(0xEB, b'\x14')
173 self._write(0x84, b'\x40')
174 self._write(0x85, b'\xFF')
175 self._write(0x86, b'\xFF')
176 self._write(0x87, b'\xFF')
177 self._write(0x88, b'\x0A')
178 self._write(0x89, b'\x21')
179 self._write(0x8A, b'\x00')
180 self._write(0x8B, b'\x80')
181 self._write(0x8C, b'\x01')
182 self._write(0x8D, b'\x01')
183 self._write(0x8E, b'\xFF')
184 self._write(0x8F, b'\xFF')
185 self._write(0xB6, b'\x00\x00')
186 self._write(0x3A, b'\x55')
187 self._write(0x90, b'\x08\x08\x08\x08')
188 self._write(0xBD, b'\x06')
189 self._write(0xBC, b'\x00')
190 self._write(0xFF, b'\x60\x01\x04')
191 self._write(0xC3, b'\x13')
192 self._write(0xC4, b'\x13')
193 self._write(0xC9, b'\x22')
194 self._write(0xBE, b'\x11')
195 self._write(0xE1, b'\x10\x0E')
196 self._write(0xDF, b'\x21\x0c\x02')
197 self._write(0xF0, b'\x45\x09\x08\x08\x26\x2A')
198 self._write(0xF1, b'\x43\x70\x72\x36\x37\x6F')
199 self._write(0xF2, b'\x45\x09\x08\x08\x26\x2A')
200 self._write(0xF3, b'\x43\x70\x72\x36\x37\x6F')
201 self._write(0xED, b'\x1B\x0B')
202 self._write(0xAE, b'\x77')
203 self._write(0xCD, b'\x63')
204 self._write(0x70, b'\x07\x07\x04\x0E\x0F\x09\x07\x08\x03')
205 self._write(0xE8, b'\x34')
206
207 self._write(
208 0x62,
209 b'\x18\x0D\x71\xED\x70\x70\x18\x0F\x71\xEF\x70\x70')
210
211 self._write(
212 0x63,
213 b'\x18\x11\x71\xF1\x70\x70\x18\x13\x71\xF3\x70\x70')
214
215 self._write(0x64, b'\x28\x29\xF1\x01\xF1\x00\x07')
216 self._write(
217 0x66,
218 b'\x3C\x00\xCD\x67\x45\x45\x10\x00\x00\x00')
219
220 self._write(
221 0x67,
222 b'\x00\x3C\x00\x00\x00\x01\x54\x10\x32\x98')
223
224 self._write(0x74, b'\x10\x85\x80\x00\x00\x4E\x00')
225 self._write(0x98, b'\x3e\x07')
226 self._write(0x35)
227 self._write(0x21)
228 self._write(0x11)
229 time.sleep_ms(120)
230
231 self._write(0x29)
232 time.sleep_ms(20)
233
234 self.rotation(self._rotation)
235
236 if backlight is not None:
237 backlight.value(1)
238
239 def _write(self, command=None, data=None):
240 """SPI write to the device: commands and data."""
241 if self.cs:
242 self.cs.off()
243
244 if command is not None:
245 self.dc.off()
246 self.spi.write(bytes([command]))
247 if data is not None:
248 self.dc.on()
249 self.spi.write(data)
250
251 if self.cs:
252 self.cs.on()
253
254 def hard_reset(self):
255 """Hard reset display."""
256 if self.reset:
257 if self.cs:
258 self.cs.off()
259
260 self.reset.on()
261 time.sleep_ms(50)
262 self.reset.off()
263 time.sleep_ms(50)
264 self.reset.on()
265 time.sleep_ms(150)
266
267 if self.cs:
268 self.cs.on()
269
270 def soft_reset(self):
271 """Soft reset display."""
272 self._write(GC9A01_SWRESET)
273 time.sleep_ms(150)
274
275 def sleep_mode(self, value):
276 """
277 Enable or disable display sleep mode.
278
279 Args:
280 value (bool): if True enable sleep mode.
281 if False disable sleep mode
282 """
283 if value:
284 self._write(GC9A01_SLPIN)
285 else:
286 self._write(GC9A01_SLPOUT)
287
288 def inversion_mode(self, value):
289 """
290 Enable or disable display inversion mode.
291
292 Args:
293 value (bool): if True enable inversion mode.
294 if False disable inversion mode
295 """
296 if value:
297 self._write(GC9A01_INVON)
298 else:
299 self._write(GC9A01_INVOFF)
300
301 def rotation(self, rotation):
302 """
303 Set display rotation.
304
305 Args:
306 rotation (int):
307
308 - 0 - PORTRAIT
309 - 1 - LANDSCAPE
310 - 2 - INVERTED PORTRAIT
311 - 3 - INVERTED LANDSCAPE
312 - 4 - PORTRAIT MIRRORED
313 - 5 - LANDSCAPE MIRRORED
314 - 6 - INVERTED PORTRAIT MIRRORED
315 - 7 - INVERTED LANDSCAPE MIRRORED
316
317 """
318
319 self._rotation = rotation % 8
320 self._write(GC9A01_MADCTL, bytes([ROTATIONS[self._rotation]]))
321
322 def _set_columns(self, start, end):
323 """
324 Send CASET (column address set) command to display.
325
326 Args:
327 start (int): column start address
328 end (int): column end address
329 """
330 if start <= end <= self.width:
331 self._write(GC9A01_CASET, _encode_pos(
332 start, end))
333
334 def _set_rows(self, start, end):
335 """
336 Send RASET (row address set) command to display.
337
338 Args:
339 start (int): row start address
340 end (int): row end address
341 """
342 if start <= end <= self.height:
343 self._write(GC9A01_RASET, _encode_pos(
344 start, end))
345
346 def _set_window(self, x0, y0, x1, y1):
347 """
348 Set window to column and row address.
349
350 Args:
351 x0 (int): column start address
352 y0 (int): row start address
353 x1 (int): column end address
354 y1 (int): row end address
355 """
356 self._set_columns(x0, x1)
357 self._set_rows(y0, y1)
358 self._write(GC9A01_RAMWR)
359
360 def vline(self, x, y, length, color):
361 """
362 Draw vertical line at the given location and color.
363
364 Args:
365 x (int): x coordinate
366 Y (int): y coordinate
367 length (int): length of line
368 color (int): 565 encoded color
369 """
370 self.fill_rect(x, y, 1, length, color)
371
372 def hline(self, x, y, length, color):
373 """
374 Draw horizontal line at the given location and color.
375
376 Args:
377 x (int): x coordinate
378 Y (int): y coordinate
379 length (int): length of line
380 color (int): 565 encoded color
381 """
382 self.fill_rect(x, y, length, 1, color)
383
384 def pixel(self, x, y, color):
385 """
386 Draw a pixel at the given location and color.
387
388 Args:
389 x (int): x coordinate
390 Y (int): y coordinate
391 color (int): 565 encoded color
392 """
393 self._set_window(x, y, x, y)
394 self._write(None, _encode_pixel(color))
395
396 def blit_buffer(self, buffer, x, y, width, height):
397 """
398 Copy buffer to display at the given location.
399
400 Args:
401 buffer (bytes): Data to copy to display
402 x (int): Top left corner x coordinate
403 Y (int): Top left corner y coordinate
404 width (int): Width
405 height (int): Height
406 """
407 self._set_window(x, y, x + width - 1, y + height - 1)
408 self._write(None, buffer)
409
410 def rect(self, x, y, w, h, color):
411 """
412 Draw a rectangle at the given location, size and color.
413
414 Args:
415 x (int): Top left corner x coordinate
416 y (int): Top left corner y coordinate
417 width (int): Width in pixels
418 height (int): Height in pixels
419 color (int): 565 encoded color
420 """
421 self.hline(x, y, w, color)
422 self.vline(x, y, h, color)
423 self.vline(x + w - 1, y, h, color)
424 self.hline(x, y + h - 1, w, color)
425
426 def fill_rect(self, x, y, width, height, color):
427 """
428 Draw a rectangle at the given location, size and filled with color.
429
430 Args:
431 x (int): Top left corner x coordinate
432 y (int): Top left corner y coordinate
433 width (int): Width in pixels
434 height (int): Height in pixels
435 color (int): 565 encoded color
436 """
437 self._set_window(x, y, x + width - 1, y + height - 1)
438 chunks, rest = divmod(width * height, _BUFFER_SIZE)
439 pixel = _encode_pixel(color)
440 self.dc.on()
441 if chunks:
442 data = pixel * _BUFFER_SIZE
443 for _ in range(chunks):
444 self._write(None, data)
445 if rest:
446 self._write(None, pixel * rest)
447
448 def fill(self, color):
449 """
450 Fill the entire FrameBuffer with the specified color.
451
452 Args:
453 color (int): 565 encoded color
454 """
455 self.fill_rect(0, 0, self.width, self.height, color)
456
457 def line(self, x0, y0, x1, y1, color):
458 """
459 Draw a single pixel wide line starting at x0, y0 and ending at x1, y1.
460
461 Args:
462 x0 (int): Start point x coordinate
463 y0 (int): Start point y coordinate
464 x1 (int): End point x coordinate
465 y1 (int): End point y coordinate
466 color (int): 565 encoded color
467 """
468 steep = abs(y1 - y0) > abs(x1 - x0)
469 if steep:
470 x0, y0 = y0, x0
471 x1, y1 = y1, x1
472 if x0 > x1:
473 x0, x1 = x1, x0
474 y0, y1 = y1, y0
475 dx = x1 - x0
476 dy = abs(y1 - y0)
477 err = dx // 2
478 if y0 < y1:
479 ystep = 1
480 else:
481 ystep = -1
482 while x0 <= x1:
483 if steep:
484 self.pixel(y0, x0, color)
485 else:
486 self.pixel(x0, y0, color)
487 err -= dy
488 if err < 0:
489 y0 += ystep
490 err += dx
491 x0 += 1
492
493 def vscrdef(self, tfa, vsa, bfa):
494 """
495 Set Vertical Scrolling Definition.
496
497 To scroll a 135x240 display these values should be 40, 240, 40.
498 There are 40 lines above the display that are not shown followed by
499 240 lines that are shown followed by 40 more lines that are not shown.
500 You could write to these areas off display and scroll them into view by
501 changing the TFA, VSA and BFA values.
502
503 Args:
504 tfa (int): Top Fixed Area
505 vsa (int): Vertical Scrolling Area
506 bfa (int): Bottom Fixed Area
507 """
508 struct.pack(">HHH")
509 self._write(GC9A01_VSCRDEF, struct.pack(">HHH", tfa, vsa, bfa))
510
511 def vscsad(self, vssa):
512 """
513 Set Vertical Scroll Start Address of RAM.
514
515 Defines which line in the Frame Memory will be written as the first
516 line after the last line of the Top Fixed Area on the display
517
518 Example:
519
520 for line in range(40, 280, 1):
521 tft.vscsad(line)
522 utime.sleep(0.01)
523
524 Args:
525 vssa (int): Vertical Scrolling Start Address
526
527 """
528 self._write(GC9A01_VSCSAD, struct.pack(">H", vssa))
529
530 def _text8(self, font, text, x0, y0, color=WHITE, background=BLACK):
531 """
532 Internal method to write characters with width of 8 and
533 heights of 8 or 16.
534
535 Args:
536 font (module): font module to use
537 text (str): text to write
538 x0 (int): column to start drawing at
539 y0 (int): row to start drawing at
540 color (int): 565 encoded color to use for characters
541 background (int): 565 encoded color to use for background
542 """
543 for char in text:
544 ch = ord(char)
545 if (font.FIRST <= ch < font.LAST
546 and x0+font.WIDTH <= self.width
547 and y0+font.HEIGHT <= self.height):
548
549 if font.HEIGHT == 8:
550 passes = 1
551 size = 8
552 each = 0
553 else:
554 passes = 2
555 size = 16
556 each = 8
557
558 for line in range(passes):
559 idx = (ch-font.FIRST)*size+(each*line)
560 #
561 # Yes, this looks bad, but it is fast
562 #
563 buffer = struct.pack(
564 '>64H',
565 color if font.FONT[idx] & _BIT7 else background,
566 color if font.FONT[idx] & _BIT6 else background,
567 color if font.FONT[idx] & _BIT5 else background,
568 color if font.FONT[idx] & _BIT4 else background,
569 color if font.FONT[idx] & _BIT3 else background,
570 color if font.FONT[idx] & _BIT2 else background,
571 color if font.FONT[idx] & _BIT1 else background,
572 color if font.FONT[idx] & _BIT0 else background,
573 color if font.FONT[idx+1] & _BIT7 else background,
574 color if font.FONT[idx+1] & _BIT6 else background,
575 color if font.FONT[idx+1] & _BIT5 else background,
576 color if font.FONT[idx+1] & _BIT4 else background,
577 color if font.FONT[idx+1] & _BIT3 else background,
578 color if font.FONT[idx+1] & _BIT2 else background,
579 color if font.FONT[idx+1] & _BIT1 else background,
580 color if font.FONT[idx+1] & _BIT0 else background,
581 color if font.FONT[idx+2] & _BIT7 else background,
582 color if font.FONT[idx+2] & _BIT6 else background,
583 color if font.FONT[idx+2] & _BIT5 else background,
584 color if font.FONT[idx+2] & _BIT4 else background,
585 color if font.FONT[idx+2] & _BIT3 else background,
586 color if font.FONT[idx+2] & _BIT2 else background,
587 color if font.FONT[idx+2] & _BIT1 else background,
588 color if font.FONT[idx+2] & _BIT0 else background,
589 color if font.FONT[idx+3] & _BIT7 else background,
590 color if font.FONT[idx+3] & _BIT6 else background,
591 color if font.FONT[idx+3] & _BIT5 else background,
592 color if font.FONT[idx+3] & _BIT4 else background,
593 color if font.FONT[idx+3] & _BIT3 else background,
594 color if font.FONT[idx+3] & _BIT2 else background,
595 color if font.FONT[idx+3] & _BIT1 else background,
596 color if font.FONT[idx+3] & _BIT0 else background,
597 color if font.FONT[idx+4] & _BIT7 else background,
598 color if font.FONT[idx+4] & _BIT6 else background,
599 color if font.FONT[idx+4] & _BIT5 else background,
600 color if font.FONT[idx+4] & _BIT4 else background,
601 color if font.FONT[idx+4] & _BIT3 else background,
602 color if font.FONT[idx+4] & _BIT2 else background,
603 color if font.FONT[idx+4] & _BIT1 else background,
604 color if font.FONT[idx+4] & _BIT0 else background,
605 color if font.FONT[idx+5] & _BIT7 else background,
606 color if font.FONT[idx+5] & _BIT6 else background,
607 color if font.FONT[idx+5] & _BIT5 else background,
608 color if font.FONT[idx+5] & _BIT4 else background,
609 color if font.FONT[idx+5] & _BIT3 else background,
610 color if font.FONT[idx+5] & _BIT2 else background,
611 color if font.FONT[idx+5] & _BIT1 else background,
612 color if font.FONT[idx+5] & _BIT0 else background,
613 color if font.FONT[idx+6] & _BIT7 else background,
614 color if font.FONT[idx+6] & _BIT6 else background,
615 color if font.FONT[idx+6] & _BIT5 else background,
616 color if font.FONT[idx+6] & _BIT4 else background,
617 color if font.FONT[idx+6] & _BIT3 else background,
618 color if font.FONT[idx+6] & _BIT2 else background,
619 color if font.FONT[idx+6] & _BIT1 else background,
620 color if font.FONT[idx+6] & _BIT0 else background,
621 color if font.FONT[idx+7] & _BIT7 else background,
622 color if font.FONT[idx+7] & _BIT6 else background,
623 color if font.FONT[idx+7] & _BIT5 else background,
624 color if font.FONT[idx+7] & _BIT4 else background,
625 color if font.FONT[idx+7] & _BIT3 else background,
626 color if font.FONT[idx+7] & _BIT2 else background,
627 color if font.FONT[idx+7] & _BIT1 else background,
628 color if font.FONT[idx+7] & _BIT0 else background
629 )
630 self.blit_buffer(buffer, x0, y0+8*line, 8, 8)
631
632 x0 += 8
633
634 def _text16(self, font, text, x0, y0, color=WHITE, background=BLACK):
635 """
636 Internal method to draw characters with width of 16 and heights of 16
637 or 32.
638
639 Args:
640 font (module): font module to use
641 text (str): text to write
642 x0 (int): column to start drawing at
643 y0 (int): row to start drawing at
644 color (int): 565 encoded color to use for characters
645 background (int): 565 encoded color to use for background
646 """
647 for char in text:
648 ch = ord(char)
649 if (font.FIRST <= ch < font.LAST
650 and x0+font.WIDTH <= self.width
651 and y0+font.HEIGHT <= self.height):
652
653 if font.HEIGHT == 16:
654 passes = 2
655 size = 32
656 each = 16
657 else:
658 passes = 4
659 size = 64
660 each = 16
661
662 for line in range(passes):
663 idx = (ch-font.FIRST)*size+(each*line)
664 #
665 # And this looks even worse, but it is fast
666 #
667 buffer = struct.pack(
668 '>128H',
669 color if font.FONT[idx] & _BIT7 else background,
670 color if font.FONT[idx] & _BIT6 else background,
671 color if font.FONT[idx] & _BIT5 else background,
672 color if font.FONT[idx] & _BIT4 else background,
673 color if font.FONT[idx] & _BIT3 else background,
674 color if font.FONT[idx] & _BIT2 else background,
675 color if font.FONT[idx] & _BIT1 else background,
676 color if font.FONT[idx] & _BIT0 else background,
677 color if font.FONT[idx+1] & _BIT7 else background,
678 color if font.FONT[idx+1] & _BIT6 else background,
679 color if font.FONT[idx+1] & _BIT5 else background,
680 color if font.FONT[idx+1] & _BIT4 else background,
681 color if font.FONT[idx+1] & _BIT3 else background,
682 color if font.FONT[idx+1] & _BIT2 else background,
683 color if font.FONT[idx+1] & _BIT1 else background,
684 color if font.FONT[idx+1] & _BIT0 else background,
685 color if font.FONT[idx+2] & _BIT7 else background,
686 color if font.FONT[idx+2] & _BIT6 else background,
687 color if font.FONT[idx+2] & _BIT5 else background,
688 color if font.FONT[idx+2] & _BIT4 else background,
689 color if font.FONT[idx+2] & _BIT3 else background,
690 color if font.FONT[idx+2] & _BIT2 else background,
691 color if font.FONT[idx+2] & _BIT1 else background,
692 color if font.FONT[idx+2] & _BIT0 else background,
693 color if font.FONT[idx+3] & _BIT7 else background,
694 color if font.FONT[idx+3] & _BIT6 else background,
695 color if font.FONT[idx+3] & _BIT5 else background,
696 color if font.FONT[idx+3] & _BIT4 else background,
697 color if font.FONT[idx+3] & _BIT3 else background,
698 color if font.FONT[idx+3] & _BIT2 else background,
699 color if font.FONT[idx+3] & _BIT1 else background,
700 color if font.FONT[idx+3] & _BIT0 else background,
701 color if font.FONT[idx+4] & _BIT7 else background,
702 color if font.FONT[idx+4] & _BIT6 else background,
703 color if font.FONT[idx+4] & _BIT5 else background,
704 color if font.FONT[idx+4] & _BIT4 else background,
705 color if font.FONT[idx+4] & _BIT3 else background,
706 color if font.FONT[idx+4] & _BIT2 else background,
707 color if font.FONT[idx+4] & _BIT1 else background,
708 color if font.FONT[idx+4] & _BIT0 else background,
709 color if font.FONT[idx+5] & _BIT7 else background,
710 color if font.FONT[idx+5] & _BIT6 else background,
711 color if font.FONT[idx+5] & _BIT5 else background,
712 color if font.FONT[idx+5] & _BIT4 else background,
713 color if font.FONT[idx+5] & _BIT3 else background,
714 color if font.FONT[idx+5] & _BIT2 else background,
715 color if font.FONT[idx+5] & _BIT1 else background,
716 color if font.FONT[idx+5] & _BIT0 else background,
717 color if font.FONT[idx+6] & _BIT7 else background,
718 color if font.FONT[idx+6] & _BIT6 else background,
719 color if font.FONT[idx+6] & _BIT5 else background,
720 color if font.FONT[idx+6] & _BIT4 else background,
721 color if font.FONT[idx+6] & _BIT3 else background,
722 color if font.FONT[idx+6] & _BIT2 else background,
723 color if font.FONT[idx+6] & _BIT1 else background,
724 color if font.FONT[idx+6] & _BIT0 else background,
725 color if font.FONT[idx+7] & _BIT7 else background,
726 color if font.FONT[idx+7] & _BIT6 else background,
727 color if font.FONT[idx+7] & _BIT5 else background,
728 color if font.FONT[idx+7] & _BIT4 else background,
729 color if font.FONT[idx+7] & _BIT3 else background,
730 color if font.FONT[idx+7] & _BIT2 else background,
731 color if font.FONT[idx+7] & _BIT1 else background,
732 color if font.FONT[idx+7] & _BIT0 else background,
733 color if font.FONT[idx+8] & _BIT7 else background,
734 color if font.FONT[idx+8] & _BIT6 else background,
735 color if font.FONT[idx+8] & _BIT5 else background,
736 color if font.FONT[idx+8] & _BIT4 else background,
737 color if font.FONT[idx+8] & _BIT3 else background,
738 color if font.FONT[idx+8] & _BIT2 else background,
739 color if font.FONT[idx+8] & _BIT1 else background,
740 color if font.FONT[idx+8] & _BIT0 else background,
741 color if font.FONT[idx+9] & _BIT7 else background,
742 color if font.FONT[idx+9] & _BIT6 else background,
743 color if font.FONT[idx+9] & _BIT5 else background,
744 color if font.FONT[idx+9] & _BIT4 else background,
745 color if font.FONT[idx+9] & _BIT3 else background,
746 color if font.FONT[idx+9] & _BIT2 else background,
747 color if font.FONT[idx+9] & _BIT1 else background,
748 color if font.FONT[idx+9] & _BIT0 else background,
749 color if font.FONT[idx+10] & _BIT7 else background,
750 color if font.FONT[idx+10] & _BIT6 else background,
751 color if font.FONT[idx+10] & _BIT5 else background,
752 color if font.FONT[idx+10] & _BIT4 else background,
753 color if font.FONT[idx+10] & _BIT3 else background,
754 color if font.FONT[idx+10] & _BIT2 else background,
755 color if font.FONT[idx+10] & _BIT1 else background,
756 color if font.FONT[idx+10] & _BIT0 else background,
757 color if font.FONT[idx+11] & _BIT7 else background,
758 color if font.FONT[idx+11] & _BIT6 else background,
759 color if font.FONT[idx+11] & _BIT5 else background,
760 color if font.FONT[idx+11] & _BIT4 else background,
761 color if font.FONT[idx+11] & _BIT3 else background,
762 color if font.FONT[idx+11] & _BIT2 else background,
763 color if font.FONT[idx+11] & _BIT1 else background,
764 color if font.FONT[idx+11] & _BIT0 else background,
765 color if font.FONT[idx+12] & _BIT7 else background,
766 color if font.FONT[idx+12] & _BIT6 else background,
767 color if font.FONT[idx+12] & _BIT5 else background,
768 color if font.FONT[idx+12] & _BIT4 else background,
769 color if font.FONT[idx+12] & _BIT3 else background,
770 color if font.FONT[idx+12] & _BIT2 else background,
771 color if font.FONT[idx+12] & _BIT1 else background,
772 color if font.FONT[idx+12] & _BIT0 else background,
773 color if font.FONT[idx+13] & _BIT7 else background,
774 color if font.FONT[idx+13] & _BIT6 else background,
775 color if font.FONT[idx+13] & _BIT5 else background,
776 color if font.FONT[idx+13] & _BIT4 else background,
777 color if font.FONT[idx+13] & _BIT3 else background,
778 color if font.FONT[idx+13] & _BIT2 else background,
779 color if font.FONT[idx+13] & _BIT1 else background,
780 color if font.FONT[idx+13] & _BIT0 else background,
781 color if font.FONT[idx+14] & _BIT7 else background,
782 color if font.FONT[idx+14] & _BIT6 else background,
783 color if font.FONT[idx+14] & _BIT5 else background,
784 color if font.FONT[idx+14] & _BIT4 else background,
785 color if font.FONT[idx+14] & _BIT3 else background,
786 color if font.FONT[idx+14] & _BIT2 else background,
787 color if font.FONT[idx+14] & _BIT1 else background,
788 color if font.FONT[idx+14] & _BIT0 else background,
789 color if font.FONT[idx+15] & _BIT7 else background,
790 color if font.FONT[idx+15] & _BIT6 else background,
791 color if font.FONT[idx+15] & _BIT5 else background,
792 color if font.FONT[idx+15] & _BIT4 else background,
793 color if font.FONT[idx+15] & _BIT3 else background,
794 color if font.FONT[idx+15] & _BIT2 else background,
795 color if font.FONT[idx+15] & _BIT1 else background,
796 color if font.FONT[idx+15] & _BIT0 else background
797 )
798 self.blit_buffer(buffer, x0, y0+8*line, 16, 8)
799 x0 += font.WIDTH
800
801 def text(self, font, text, x0, y0, color=WHITE, background=BLACK):
802 """
803 Draw text on display in specified font and colors. 8 and 16 bit wide
804 fonts are supported.
805
806 Args:
807 font (module): font module to use.
808 text (str): text to write
809 x0 (int): column to start drawing at
810 y0 (int): row to start drawing at
811 color (int): 565 encoded color to use for characters
812 background (int): 565 encoded color to use for background
813 """
814 if font.WIDTH == 8:
815 self._text8(font, text, x0, y0, color, background)
816 else:
817 self._text16(font, text, x0, y0, color, background)
818
819 def bitmap(self, bitmap, x, y, index=0):
820 """
821 Draw a bitmap on display at the specified column and row
822
823 Args:
824 bitmap (bitmap_module): The module containing the bitmap to draw
825 x (int): column to start drawing at
826 y (int): row to start drawing at
827 index (int): Optional index of bitmap to draw from multiple bitmap
828 module
829
830 """
831 bitmap_size = bitmap.HEIGHT * bitmap.WIDTH
832 buffer_len = bitmap_size * 2
833 buffer = bytearray(buffer_len)
834 bs_bit = bitmap.BPP * bitmap_size * index if index > 0 else 0
835
836 for i in range(0, buffer_len, 2):
837 color_index = 0
838 for bit in range(bitmap.BPP):
839 color_index <<= 1
840 color_index |= (bitmap.BITMAP[bs_bit // 8]
841 & 1 << (7 - (bs_bit % 8))) > 0
842 bs_bit += 1
843
844 color = bitmap.PALETTE[color_index]
845 buffer[i] = color & 0xff00 >> 8
846 buffer[i + 1] = color_index & 0xff
847
848 self.blit_buffer(buffer, x, y, bitmap.WIDTH, bitmap.HEIGHT)
849
850 # @micropython.native
851 def write(self, font, string, x, y, fg=WHITE, bg=BLACK):
852 """
853 Write a string using a converted true-type font on the display starting
854 at the specified column and row
855
856 Args:
857 font (font): The module containing the converted true-type font
858 s (string): The string to write
859 x (int): column to start writing
860 y (int): row to start writing
861 fg (int): foreground color, optional, defaults to WHITE
862 bg (int): background color, optional, defaults to BLACK
863 """
864 buffer_len = font.HEIGHT * font.MAX_WIDTH * 2
865 buffer = bytearray(buffer_len)
866 fg_hi = (fg & 0xff00) >> 8
867 fg_lo = fg & 0xff
868
869 bg_hi = (bg & 0xff00) >> 8
870 bg_lo = bg & 0xff
871
872 for character in string:
873 try:
874 char_index = font.MAP.index(character)
875 offset = char_index * font.OFFSET_WIDTH
876 bs_bit = font.OFFSETS[offset]
877 if font.OFFSET_WIDTH > 1:
878 bs_bit = (bs_bit << 8) + font.OFFSETS[offset + 1]
879
880 if font.OFFSET_WIDTH > 2:
881 bs_bit = (bs_bit << 8) + font.OFFSETS[offset + 2]
882
883 char_width = font.WIDTHS[char_index]
884 buffer_needed = char_width * font.HEIGHT * 2
885
886 for i in range(0, buffer_needed, 2):
887 if font.BITMAPS[bs_bit // 8] & 1 << (7 - (bs_bit % 8)) > 0:
888 buffer[i] = fg_hi
889 buffer[i + 1] = fg_lo
890 else:
891 buffer[i] = bg_hi
892 buffer[i + 1] = bg_lo
893
894 bs_bit += 1
895
896 to_col = x + char_width - 1
897 to_row = y + font.HEIGHT - 1
898 if self.width > to_col and self.height > to_row:
899 self._set_window(x, y, to_col, to_row)
900 self._write(None, buffer[0:buffer_needed])
901
902 x += char_width
903
904 except ValueError:
905 pass
906
907 def write_width(self, font, string):
908 """
909 Returns the width in pixels of the string if it was written with the
910 specified font
911
912 Args:
913 font (font): The module containing the converted true-type font
914 string (string): The string to measure
915 """
916 width = 0
917 for character in string:
918 try:
919 char_index = font.MAP.index(character)
920 width += font.WIDTHS[char_index]
921
922 except ValueError:
923 pass
924
925 return width