├── .gitignore ├── LICENSE ├── README.md ├── docs ├── ST7789.jpg ├── astrol.svg ├── cyrilc.svg ├── gotheng.svg ├── gothger.svg ├── gothita.svg ├── greekc.svg ├── greekcs.svg ├── greekp.svg ├── greeks.svg ├── italicc.svg ├── italiccs.svg ├── italict.svg ├── japan.svg ├── lowmat.svg ├── madctl_0.png ├── madctl_v.png ├── madctl_vx.png ├── madctl_vxy.png ├── madctl_vy.png ├── madctl_x.png ├── madctl_xy.png ├── madctl_y.png ├── marker.svg ├── meteo.svg ├── misc.svg ├── music.svg ├── romanc.svg ├── romancs.svg ├── romand.svg ├── romanp.svg ├── romans.svg ├── romant.svg ├── scriptc.svg ├── scripts.svg ├── symbol.svg ├── uppmat.svg ├── vga1_16x16.png ├── vga1_16x32.png ├── vga1_8x16.png ├── vga1_8x8.png ├── vga1_bold_16x16.png ├── vga1_bold_16x32.png ├── vga2_16x16.png ├── vga2_16x32.png ├── vga2_8x16.png ├── vga2_8x8.png ├── vga2_bold_16x16.png └── vga2_bold_16x32.png ├── examples ├── README.md ├── bitarray.py ├── bitmap_fonts.py ├── chango │ ├── chango.py │ ├── chango_16.py │ ├── chango_32.py │ ├── chango_64.py │ └── make_fonts_py.sh ├── clock │ ├── OFL.txt │ ├── Pacifico-Regular.ttf │ ├── clock.py │ ├── clock_320x170 │ │ ├── nasa01.jpg │ │ ├── nasa02.jpg │ │ ├── nasa03.jpg │ │ ├── nasa04.jpg │ │ ├── nasa05.jpg │ │ ├── nasa06.jpg │ │ ├── nasa07.jpg │ │ ├── nasa08.jpg │ │ ├── nasa09.jpg │ │ ├── nasa10.jpg │ │ ├── nasa11.jpg │ │ ├── nasa12.jpg │ │ ├── nasa13.jpg │ │ ├── nasa14.jpg │ │ ├── nasa15.jpg │ │ ├── nasa16.jpg │ │ ├── nasa17.jpg │ │ ├── nasa18.jpg │ │ ├── nasa19.jpg │ │ ├── nasa20.jpg │ │ ├── nasa21.jpg │ │ ├── nasa22.jpg │ │ ├── nasa23.jpg │ │ ├── nasa24.jpg │ │ └── nasa25.jpg │ └── pacifico90.py ├── feathers.py ├── font_decode.py ├── hello.py ├── hershey.py ├── jpg │ ├── bigbuckbunny-128x128.jpg │ ├── bigbuckbunny-160x128.jpg │ ├── bigbuckbunny-240x135.jpg │ ├── bigbuckbunny-240x240.jpg │ ├── bigbuckbunny-320x170.jpg │ ├── bigbuckbunny-320x240.jpg │ └── jpg.py ├── mono_fonts │ ├── inconsolata_16.py │ ├── inconsolata_32.py │ ├── inconsolata_64.py │ └── mono_fonts.py ├── noto_fonts.py ├── pinball.py ├── png │ ├── alien.png │ └── alien.py ├── proverbs │ ├── NotoSansSC-Regular.otf │ ├── makefont │ ├── proverbs.py │ └── proverbs_font.py ├── roids.py ├── scroll.py ├── st7789.pyi ├── tft_buttons.py ├── tft_config.py ├── tiny_toasters │ ├── tiny_toasters.py │ ├── ttoast_bitmaps.py │ └── ttoasters.bmp ├── toasters │ ├── maketoast │ ├── t1.png │ ├── t2.png │ ├── t3.png │ ├── t4.png │ ├── t5.png │ ├── toast_bitmaps.py │ ├── toasters.bmp │ └── toasters.py ├── toasters_jpg │ ├── toaster.jpg │ └── toasters_jpg.py └── watch │ ├── LibreBaskerville-Regular.ttf │ ├── create_face_jpg.py │ ├── face_320x170.jpg │ └── watch.py ├── firmware ├── LICENSE └── firmware.bin ├── fonts ├── bitmap │ ├── README.md │ ├── vga1_16x16.py │ ├── vga1_16x32.py │ ├── vga1_8x16.py │ ├── vga1_8x8.py │ ├── vga1_bold_16x16.py │ ├── vga1_bold_16x32.py │ ├── vga2_16x16.py │ ├── vga2_16x32.py │ ├── vga2_8x16.py │ ├── vga2_8x8.py │ ├── vga2_bold_16x16.py │ ├── vga2_bold_16x32.py │ ├── vga_8x16.bin │ └── vga_8x8.bin ├── truetype │ ├── Chango-Regular.ttf │ ├── LICENSE_OFL.txt │ ├── NotoSans-Regular.ttf │ ├── NotoSansMono-Regular.ttf │ ├── NotoSansMono_32.py │ ├── NotoSans_32.py │ ├── NotoSerif-Regular.ttf │ ├── NotoSerif_32.py │ ├── README.md │ └── inconsolata-700.ttf └── vector │ ├── README.md │ ├── astrol.py │ ├── cyrilc.py │ ├── gotheng.py │ ├── gothger.py │ ├── gothita.py │ ├── greekc.py │ ├── greekcs.py │ ├── greekp.py │ ├── greeks.py │ ├── italicc.py │ ├── italiccs.py │ ├── italict.py │ ├── lowmat.py │ ├── marker.py │ ├── meteo.py │ ├── music.py │ ├── romanc.py │ ├── romancs.py │ ├── romand.py │ ├── romanp.py │ ├── romans.py │ ├── romant.py │ ├── scriptc.py │ ├── scripts.py │ ├── symbol.py │ └── uppmat.py ├── manifest.py ├── modules ├── NotoSansMono_32.py ├── NotoSans_32.py ├── NotoSerif_32.py ├── axp202c.py ├── df.py ├── focaltouch.py ├── greekc.py ├── greekcs.py ├── greekp.py ├── greeks.py ├── inconsolata_16.py ├── inconsolata_32.py ├── italicc.py ├── italiccs.py ├── italict.py ├── marker.py ├── meteo.py ├── mf.py ├── music.py ├── romanc.py ├── romancs.py ├── romand.py ├── romanp.py ├── romans.py ├── romant.py ├── scriptc.py ├── scripts.py ├── sdcard.py ├── symbol.py ├── vga1_16x16.py ├── vga1_16x32.py ├── vga1_8x16.py ├── vga1_8x8.py ├── vga1_bold_16x16.py ├── vga1_bold_16x32.py ├── vga2_16x16.py ├── vga2_8x16.py ├── vga2_8x8.py ├── vga2_bold_16x16.py └── vga2_bold_16x32.py ├── st7789 ├── .clang-format ├── jpg │ ├── tjpgd565.c │ └── tjpgd565.h ├── micropython.cmake ├── mpfile.c ├── mpfile.h ├── png │ ├── miniz.c │ ├── miniz.h │ ├── pngle.c │ └── pngle.h ├── st7789.c └── st7789.h └── utils ├── font2bitmap.py ├── font_from_romfont.py ├── howto-convert-to-jpg ├── imgtobitmap.py ├── monofont2bitmap.py ├── png_from_font.py ├── requirements.txt ├── sprites2bitmap.py └── wi-alien.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .idea 3 | __pycache__ 4 | sphinx/build 5 | *~ 6 | *.pyc 7 | *.o 8 | *.P 9 | .DS_Store 10 | .history 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2020, 2021, 2022 Russ Hughes 3 | 4 | These files incorporate work covered by the following copyright and 5 | permission notice and are 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 | -------------------------------------------------------------------------------- /docs/ST7789.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/ST7789.jpg -------------------------------------------------------------------------------- /docs/madctl_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_0.png -------------------------------------------------------------------------------- /docs/madctl_v.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_v.png -------------------------------------------------------------------------------- /docs/madctl_vx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_vx.png -------------------------------------------------------------------------------- /docs/madctl_vxy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_vxy.png -------------------------------------------------------------------------------- /docs/madctl_vy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_vy.png -------------------------------------------------------------------------------- /docs/madctl_x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_x.png -------------------------------------------------------------------------------- /docs/madctl_xy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_xy.png -------------------------------------------------------------------------------- /docs/madctl_y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/madctl_y.png -------------------------------------------------------------------------------- /docs/vga1_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga1_16x16.png -------------------------------------------------------------------------------- /docs/vga1_16x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga1_16x32.png -------------------------------------------------------------------------------- /docs/vga1_8x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga1_8x16.png -------------------------------------------------------------------------------- /docs/vga1_8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga1_8x8.png -------------------------------------------------------------------------------- /docs/vga1_bold_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga1_bold_16x16.png -------------------------------------------------------------------------------- /docs/vga1_bold_16x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga1_bold_16x32.png -------------------------------------------------------------------------------- /docs/vga2_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga2_16x16.png -------------------------------------------------------------------------------- /docs/vga2_16x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga2_16x32.png -------------------------------------------------------------------------------- /docs/vga2_8x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga2_8x16.png -------------------------------------------------------------------------------- /docs/vga2_8x8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga2_8x8.png -------------------------------------------------------------------------------- /docs/vga2_bold_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga2_bold_16x16.png -------------------------------------------------------------------------------- /docs/vga2_bold_16x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/docs/vga2_bold_16x32.png -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Example Programs 2 | 3 | 4 | ## bitarray.py 5 | 6 | An example using map_bitarray_to_rgb565 to draw sprites 7 | 8 | 9 | ## bitmap_fonts.py 10 | 11 | Cycles through all characters of four bitmap fonts on the display 12 | 13 | ## chango.py 14 | 15 | Proportional font test for font2bitmap converter. 16 | 17 | 18 | ## clock.py 19 | 20 | Displays a clock over a background image on the display. 21 | 22 | The buttons on the module can be used to set the time. 23 | 24 | Background images courtesy of the NASA image and video gallery available at 25 | https://images.nasa.gov/ 26 | 27 | The Font is Copyright 2018 The Pacifico Project Authors (https://github.com/googlefonts/Pacifico) 28 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 29 | This license is copied below, and is also available with a FAQ at: 30 | http://scripts.sil.org/OFL 31 | 32 | 33 | ## feathers.py 34 | 35 | Smoothly scroll rainbow-colored mirrored random curves across the display. 36 | 37 | 38 | ## hello.py 39 | 40 | Writes "Hello!" in random colors at random locations on the display. 41 | 42 | 43 | ## hershey.py 44 | 45 | Demo program that draws greetings on display cycling thru hershey fonts and colors. 46 | 47 | ## jpg.py 48 | 49 | Draw a full screen jpg using the slower but less memory intensive method of blitting 50 | each Minimum Coded Unit (MCU) block. Usually 8×8pixels but can be other multiples of 8. 51 | 52 | bigbuckbunny.jpg (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org 53 | 54 | 55 | ### mono_fonts.py 56 | mono_fonts.py test for monofont2bitmap converter and bitmap method. This is the older method of 57 | converting monofonts to bitmaps. See the newer method in prop_fonts/chango.py that works with 58 | mono and proportional fonts using the write method. 59 | 60 | 61 | ## noto_fonts.py 62 | 63 | Writes the names of three Noto fonts centered on the display 64 | using the font. The fonts were converted from True Type fonts using 65 | the font2bitmap utility. 66 | 67 | 68 | ## proverbs.py 69 | 70 | Displays what I hope are chinese proverbs in simplified chinese to test UTF-8 font support. 71 | 72 | 73 | ## roids.py 74 | 75 | Asteroids style game demo using polygons. 76 | 77 | 78 | ## scroll.py 79 | 80 | Smoothly scroll all characters of a font up the display. 81 | Fonts heights must be even multiples of the screen height (i.e. 8 or 16 pixels high). 82 | 83 | 84 | ## tiny_toasters.py 85 | 86 | Flying Tiny Toasters for smaller displays (like the ST7735) 87 | 88 | Uses spritesheet from CircuitPython_Flying_Toasters pendant project 89 | https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 90 | 91 | Convert spritesheet bmp to tft.bitmap() method compatible python module using: 92 | python3 ./sprites2bitmap.py ttoasters.bmp 32 32 4 > ttoast_bitmaps.py 93 | 94 | 95 | ## toasters.py 96 | 97 | Flying Toasters 98 | 99 | Uses spritesheet from CircuitPython_Flying_Toasters pendant project 100 | https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 101 | 102 | Convert spritesheet bmp to tft.bitmap() method compatible python module using: 103 | python3 ./sprites2bitmap.py toasters.bmp 64 64 4 > toast_bitmaps.py 104 | 105 | 106 | ## toasters_jpg.py 107 | 108 | An example using a jpg sprite map to draw sprites on T-Display. This is an older version of the 109 | toasters.py and tiny_toasters example. It uses the jpg_decode() method to grab a bitmap of each 110 | sprite from the toaster.jpg sprite sheet. 111 | 112 | Youtube video: https://youtu.be/0uWsjKQmCpU 113 | 114 | spritesheet from CircuitPython_Flying_Toasters 115 | https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 116 | 117 | 118 | ## watch.py 119 | 120 | Analog Watch Display using jpg for the face and filled polygons for the hands 121 | Requires face_{width}x{height}.jpg in the same directory as this script. See the create_face.py 122 | script for creating a face image for a given sized display. 123 | 124 | Previous version video: https://youtu.be/NItKb6umMc4 125 | -------------------------------------------------------------------------------- /examples/bitarray.py: -------------------------------------------------------------------------------- 1 | """ 2 | bitarray.py 3 | 4 | An example using map_bitarray_to_rgb565 to draw sprites 5 | 6 | """ 7 | 8 | import time 9 | import random 10 | import st7789 11 | import tft_config 12 | 13 | 14 | tft = tft_config.config(1) 15 | 16 | 17 | SPRITE_WIDTH = 16 18 | SPRITE_HEIGHT = 16 19 | SPRITE_STEPS = 3 20 | SPRITE_BITMAPS = [ 21 | bytearray([ 22 | 0b00000000, 0b00000000, 23 | 0b00000001, 0b11110000, 24 | 0b00000111, 0b11110000, 25 | 0b00001111, 0b11100000, 26 | 0b00001111, 0b11000000, 27 | 0b00011111, 0b10000000, 28 | 0b00011111, 0b00000000, 29 | 0b00011110, 0b00000000, 30 | 0b00011111, 0b00000000, 31 | 0b00011111, 0b10000000, 32 | 0b00001111, 0b11000000, 33 | 0b00001111, 0b11100000, 34 | 0b00000111, 0b11110000, 35 | 0b00000001, 0b11110000, 36 | 0b00000000, 0b00000000, 37 | 0b00000000, 0b00000000]), 38 | 39 | bytearray([ 40 | 0b00000000, 0b00000000, 41 | 0b00000011, 0b11100000, 42 | 0b00001111, 0b11111000, 43 | 0b00011111, 0b11111100, 44 | 0b00011111, 0b11111100, 45 | 0b00111111, 0b11110000, 46 | 0b00111111, 0b10000000, 47 | 0b00111100, 0b00000000, 48 | 0b00111111, 0b10000000, 49 | 0b00111111, 0b11110000, 50 | 0b00011111, 0b11111100, 51 | 0b00011111, 0b11111100, 52 | 0b00001111, 0b11111000, 53 | 0b00000011, 0b11100000, 54 | 0b00000000, 0b00000000, 55 | 0b00000000, 0b00000000]), 56 | 57 | bytearray([ 58 | 0b00000000, 0b00000000, 59 | 0b00000111, 0b11000000, 60 | 0b00011111, 0b11110000, 61 | 0b00111111, 0b11111000, 62 | 0b00111111, 0b11111000, 63 | 0b01111111, 0b11111100, 64 | 0b01111111, 0b11111100, 65 | 0b01111111, 0b11111100, 66 | 0b01111111, 0b11111100, 67 | 0b01111111, 0b11111100, 68 | 0b00111111, 0b11111000, 69 | 0b00111111, 0b11111000, 70 | 0b00011111, 0b11110000, 71 | 0b00000111, 0b11000000, 72 | 0b00000000, 0b00000000, 73 | 0b00000000, 0b00000000]), 74 | 75 | bytearray([ 76 | 0b00000000, 0b00000000, 77 | 0b00000000, 0b00000000, 78 | 0b00000000, 0b00000000, 79 | 0b00000000, 0b00000000, 80 | 0b00000000, 0b00000000, 81 | 0b00000000, 0b00000000, 82 | 0b00000000, 0b00000000, 83 | 0b00000000, 0b00000000, 84 | 0b00000000, 0b00000000, 85 | 0b00000000, 0b00000000, 86 | 0b00000000, 0b00000000, 87 | 0b00000000, 0b00000000, 88 | 0b00000000, 0b00000000, 89 | 0b00000000, 0b00000000, 90 | 0b00000000, 0b00000000, 91 | 0b00000000, 0b00000000])] 92 | 93 | 94 | def collide(sprite_a, sprite_b): 95 | '''return true if two sprites overlap''' 96 | 97 | return ( 98 | sprite_a.x + sprite_a.width >= sprite_b.x and 99 | sprite_a.x <= sprite_b.x + sprite_b.width and 100 | sprite_a.y + sprite_a.height >= sprite_b.y and 101 | sprite_a.y <= sprite_b.y + sprite_b.height) 102 | 103 | 104 | class pacman(): 105 | ''' 106 | pacman class to keep track of a sprites locaton and step 107 | ''' 108 | def __init__(self, sprites, width, height, steps): 109 | """create a new pacman sprite that does not overlap another sprite""" 110 | self.steps = steps 111 | self.step = random.randint(0, self.steps) 112 | self.width = width 113 | self.height = height 114 | 115 | # Big problem if there are too many sprites for the size of the display 116 | while True: 117 | self.x = random.randint(0, tft.width() - width) 118 | self.y = random.randint(0, tft.height() - height) 119 | # if this sprite does not overlap another sprite then break 120 | if not any(collide(self, sprite) for sprite in sprites): 121 | break 122 | 123 | def move(self): 124 | '''move the sprite one step''' 125 | max = tft.width() - SPRITE_WIDTH 126 | self.step += 1 127 | self.step %= SPRITE_STEPS 128 | self.x += 1 129 | if self.x == max - 1: 130 | self.step = SPRITE_STEPS 131 | 132 | self.x %= max 133 | 134 | def draw(self, blitable): 135 | tft.blit_buffer(blitable, self.x, self.y, self.width, self.height) 136 | 137 | def main(): 138 | ''' 139 | Draw on screen using map_bitarray_to_rgb565 140 | ''' 141 | 142 | try: 143 | # enable display and clear screen 144 | tft.init() 145 | tft.fill(st7789.BLACK) 146 | 147 | # convert bitmaps into rgb565 blitable buffers 148 | blitable = [] 149 | for sprite_bitmap in SPRITE_BITMAPS: 150 | sprite = bytearray(512) 151 | tft.map_bitarray_to_rgb565( 152 | sprite_bitmap, 153 | sprite, 154 | SPRITE_WIDTH, 155 | st7789.YELLOW, 156 | st7789.BLACK) 157 | blitable.append(sprite) 158 | 159 | sprite_count = tft.width() // SPRITE_WIDTH * tft.height() // SPRITE_HEIGHT // 4 160 | 161 | # create pacman spites in random positions 162 | sprites = [pacman(sprites, SPRITE_WIDTH, SPRITE_HEIGHT, SPRITE_STEPS) for _ in range(sprite_count)] 163 | 164 | # move and draw sprites 165 | while True: 166 | for sprite in sprites: 167 | sprite.move() 168 | sprite.draw(blitable[sprite.step]) 169 | time.sleep(0.05) 170 | 171 | finally: 172 | tft.deinit() 173 | 174 | main() 175 | -------------------------------------------------------------------------------- /examples/bitmap_fonts.py: -------------------------------------------------------------------------------- 1 | """ 2 | fonts.py 3 | 4 | Cycles through all characters of four bitmap fonts on the display 5 | 6 | """ 7 | 8 | import utime 9 | import st7789 10 | import tft_config 11 | import vga1_8x8 as font1 12 | import vga1_8x16 as font2 13 | import vga1_bold_16x16 as font3 14 | import vga1_bold_16x32 as font4 15 | 16 | 17 | tft = tft_config.config(0) 18 | 19 | 20 | def main(): 21 | 22 | try: 23 | tft.init() 24 | 25 | while True: 26 | for font in (font1, font2, font3, font4): 27 | tft.fill(st7789.BLUE) 28 | line = 0 29 | col = 0 30 | for char in range(font.FIRST, font.LAST): 31 | tft.text(font, chr(char), col, line, st7789.WHITE, st7789.BLUE) 32 | col += font.WIDTH 33 | if col > tft.width() - font.WIDTH: 34 | col = 0 35 | line += font.HEIGHT 36 | 37 | if line > tft.height()-font.HEIGHT: 38 | utime.sleep(3) 39 | tft.fill(st7789.BLUE) 40 | line = 0 41 | col = 0 42 | 43 | utime.sleep(3) 44 | 45 | finally: 46 | tft.deinit() 47 | 48 | main() 49 | -------------------------------------------------------------------------------- /examples/chango/chango.py: -------------------------------------------------------------------------------- 1 | """ 2 | chango.py proportional font test for font2bitmap converter. 3 | """ 4 | 5 | import time 6 | import gc 7 | import st7789 8 | import tft_config 9 | 10 | tft = tft_config.config(1) 11 | 12 | # 13 | # Large fonts take alot of memory, they should be frozen in the 14 | # firmaware or compiled using the mpy-cross compiler. 15 | # 16 | 17 | import chango_16 as font_16 18 | import chango_32 as font_32 19 | import chango_64 as font_64 20 | 21 | gc.collect() 22 | 23 | def display_font(font): 24 | 25 | tft.fill(st7789.BLUE) # clear the screen 26 | column = 0 # first column 27 | row = 0 # first row 28 | 29 | for char in font.MAP: # for each character in the font map 30 | width = tft.write_len(font, char) # get the width of the character 31 | 32 | if column + width > tft.width(): # if the character will not fit on the current line 33 | row += font.HEIGHT # move to the next row 34 | column = 0 # reset the column 35 | 36 | if row+font.HEIGHT > tft.height(): # if the row will not fit on the screen 37 | time.sleep(1) # pause for a second 38 | tft.fill(st7789.BLUE) # clear the screen 39 | row = 0 # reset the row 40 | 41 | tft.write( # write to the screen 42 | font, # in this font 43 | char, # the character 44 | column, # at this column 45 | row, # on this row 46 | st7789.WHITE, # in white 47 | st7789.BLUE) # with blue background 48 | 49 | column += width # move the column past the character 50 | 51 | def main(): 52 | try: 53 | tft.init() 54 | tft.fill(st7789.BLUE) 55 | 56 | for font in [font_16, font_32, font_64]: # for each font 57 | display_font(font) # display the font characters 58 | time.sleep(1) # pause for a second 59 | 60 | finally: 61 | tft.deinit() 62 | 63 | main() 64 | -------------------------------------------------------------------------------- /examples/chango/make_fonts_py.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ../../utils/font2bitmap.py ../../fonts/truetype/Chango-Regular.ttf 16 -c 0x20-0x7f > chango_16.py 4 | ../../utils/font2bitmap.py ../../fonts/truetype/Chango-Regular.ttf 32 -c 0x20-0x7f > chango_32.py 5 | ../../utils/font2bitmap.py ../../fonts/truetype/Chango-Regular.ttf 64 -c 0x20-0x7f > chango_64.py 6 | 7 | mpy-cross chango_16.py 8 | mpy-cross chango_32.py 9 | mpy-cross chango_64.py 10 | 11 | -------------------------------------------------------------------------------- /examples/clock/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018 The Pacifico Project Authors (https://github.com/googlefonts/Pacifico) 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /examples/clock/Pacifico-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/Pacifico-Regular.ttf -------------------------------------------------------------------------------- /examples/clock/clock.py: -------------------------------------------------------------------------------- 1 | """ 2 | clock.py 3 | 4 | Displays a clock over a background image on the display. 5 | 6 | The buttons on the module can be used to set the time. 7 | 8 | Background images courtesy of the NASA image and video gallery available at 9 | https://images.nasa.gov/ 10 | 11 | The Font is Copyright 2018 The Pacifico Project Authors (https://github.com/googlefonts/Pacifico) 12 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 13 | This license is copied below, and is also available with a FAQ at: 14 | http://scripts.sil.org/OFL 15 | 16 | """ 17 | import gc 18 | import utime 19 | from machine import Pin, SPI, RTC 20 | import st7789 21 | import tft_config 22 | import tft_buttons 23 | import pacifico90 as font 24 | 25 | buttons = tft_buttons.Buttons() 26 | 27 | tft = tft_config.config(1) 28 | rtc = RTC() 29 | background_lock = 0 # prevents background change while > 0 30 | 31 | def cycle(p): 32 | """return the next item in a list""" 33 | try: 34 | len(p) 35 | except TypeError: 36 | cache = [] 37 | for i in p: 38 | yield i 39 | cache.append(i) 40 | 41 | p = cache 42 | while p: 43 | yield from p 44 | 45 | 46 | class Button: 47 | """ 48 | Debounced pin handler 49 | 50 | Modifed from https://gist.github.com/jedie/8564e62b0b8349ff9051d7c5a1312ed7 51 | """ 52 | def __init__(self, pin, callback, trigger=Pin.IRQ_FALLING, debounce=350): 53 | self.callback = callback 54 | self.debounce = debounce 55 | self._next_call = utime.ticks_ms() + self.debounce 56 | pin.irq(trigger=trigger, handler=self.debounce_handler) 57 | 58 | def call_callback(self, pin): 59 | self.callback(pin) 60 | 61 | def debounce_handler(self, pin): 62 | if utime.ticks_ms() > self._next_call: 63 | self._next_call = utime.ticks_ms() + self.debounce 64 | self.call_callback(pin) 65 | 66 | def hour_pressed(pin): 67 | global background_lock, rtc 68 | tm = rtc.datetime() 69 | rtc.init((tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]+1, tm[6], tm[7])) 70 | background_lock = 10 71 | 72 | def minute_pressed(pin): 73 | global background_lock, rtc 74 | tm = rtc.datetime() 75 | rtc.init((tm[0], tm[1], tm[2], tm[3], tm[4]+1, tm[5], tm[6], tm[7])) 76 | background_lock = 10 77 | 78 | 79 | def main(): 80 | """ 81 | Initialize the display and show the time 82 | """ 83 | global background_lock 84 | 85 | try: 86 | tft.init() 87 | 88 | # image, Time Column, Time Row, Time Color 89 | backgrounds = cycle([ 90 | 'nasa01.jpg', 'nasa02.jpg', 'nasa03.jpg', 'nasa04.jpg', 'nasa05.jpg', 91 | 'nasa06.jpg', 'nasa07.jpg', 'nasa08.jpg', 'nasa09.jpg', 'nasa10.jpg', 92 | 'nasa11.jpg', 'nasa12.jpg', 'nasa13.jpg', 'nasa14.jpg', 'nasa15.jpg', 93 | 'nasa16.jpg', 'nasa17.jpg', 'nasa18.jpg', 'nasa19.jpg', 'nasa20.jpg', 94 | 'nasa21.jpg', 'nasa22.jpg', 'nasa23.jpg', 'nasa24.jpg', 'nasa25.jpg']) 95 | 96 | digit_columns = [] 97 | background_change = True 98 | time_col = tft.width()//2 - font.MAX_WIDTH * 5 //2 99 | time_row = tft.height()//2 - font.HEIGHT //2 100 | time_color = st7789.WHITE 101 | last_time = "-----" 102 | 103 | # 104 | # change these to match your button connections 105 | # 106 | 107 | Button(pin=buttons.left, callback=hour_pressed) 108 | Button(pin=buttons.right, callback=minute_pressed) 109 | 110 | while True: 111 | 112 | # create new digit_backgrounds and change the background image 113 | if background_change: 114 | image = next(backgrounds) 115 | background_change = False 116 | 117 | # clear the old backgrounds and gc 118 | digit_background = [] 119 | gc.collect() 120 | 121 | # draw the new background from the clock_{WIDTH}x{HEIGHT} directory 122 | image_file = f"clock_{tft.width()}x{tft.height()}/{image}" 123 | tft.jpg(image_file, 0, 0, st7789.FAST) 124 | 125 | # calculate the starting column for each time digit 126 | digit_columns = [time_col + digit * 127 | font.MAX_WIDTH for digit in range(5)] 128 | 129 | # nudge the ':' to the right since it is narrower then the digits 130 | digit_columns[2] += font.MAX_WIDTH // 4 131 | 132 | # get the background bitmap behind each clock digit from the jpg file and store it 133 | # in a list so it can be used to write each digit simulating transparency. 134 | digit_background = [ 135 | tft.jpg_decode( 136 | image_file, # jpg file name 137 | digit_columns[digit], # column to start bitmap at 138 | time_row, # row to start bitmap at 139 | font.MAX_WIDTH, # width of bitmap to save 140 | font.HEIGHT) # height of bitmap to save 141 | for digit in range(5) 142 | ] 143 | 144 | # cause all digits to be updated 145 | last_time = "-----" 146 | 147 | # get the current hour and minute 148 | _, _, _, hour, minute, second, _, _ = utime.localtime() 149 | 150 | # 12 hour time 151 | if hour == 0: 152 | hour = 12 153 | if hour > 12: 154 | hour -= 12 155 | 156 | # format time string as "HH:MM" 157 | time_fmt = "{:02d}:{:02d}" if second % 2 == 0 else "{:02d} {:02d}" 158 | time = time_fmt.format(hour, minute) 159 | 160 | # loop through the time string 161 | for digit in range(5): 162 | 163 | # Check if this digit has changed 164 | if time[digit] != last_time[digit]: 165 | 166 | # digit 1 is the hour, change the background every hour 167 | # digit 3 is the tens of the minute, change the background every 10 minutes 168 | # digit 4 is the ones of the minute, change the background every minute 169 | if digit == 4 and last_time[digit] != '-' and background_lock == 0: 170 | background_change = True 171 | 172 | # draw the changed digit, don't fill to the right 173 | # of the ':' because it is always the same width 174 | tft.write( 175 | font, # the font to write to the display 176 | time[digit], # time string digit to write 177 | digit_columns[digit], # write to the correct column 178 | time_row, # write on row 179 | time_color, # color of time text 180 | st7789.BLACK, # transparent background color 181 | digit_background[digit], # use the background bitmap 182 | digit != 2) # don't fill to the right of the ':' 183 | 184 | # save the current time 185 | last_time = time 186 | 187 | # decrement the background lock 188 | if background_lock: 189 | background_lock -= 1 190 | 191 | utime.sleep(0.5) 192 | gc.collect() 193 | 194 | finally: 195 | tft.deinit() 196 | 197 | main() 198 | -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa01.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa02.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa03.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa04.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa05.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa06.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa06.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa07.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa08.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa09.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa10.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa11.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa12.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa13.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa14.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa15.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa16.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa17.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa18.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa19.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa20.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa21.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa22.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa23.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa24.jpg -------------------------------------------------------------------------------- /examples/clock/clock_320x170/nasa25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/clock/clock_320x170/nasa25.jpg -------------------------------------------------------------------------------- /examples/feathers.py: -------------------------------------------------------------------------------- 1 | """ 2 | feathers.py 3 | Smoothly scroll rainbow-colored mirrored random curves across the display. 4 | """ 5 | 6 | import random 7 | import math 8 | import utime 9 | import st7789 10 | import tft_config 11 | 12 | def between(left, right, along): 13 | """returns a point along the curve from left to right""" 14 | dist = (1 - math.cos(along * math.pi)) / 2 15 | return left * (1 - dist) + right * dist 16 | 17 | 18 | def color_wheel(position): 19 | """returns a 565 color from the given position of the color wheel""" 20 | position = (255 - position) % 255 21 | 22 | if position < 85: 23 | return st7789.color565(255 - position * 3, 0, position * 3) 24 | 25 | if position < 170: 26 | position -= 85 27 | return st7789.color565(0, position * 3, 255 - position * 3) 28 | 29 | position -= 170 30 | return st7789.color565(position * 3, 255 - position * 3, 0) 31 | 32 | 33 | def main(): 34 | ''' 35 | The big show! 36 | ''' 37 | try: 38 | tft = tft_config.config(1) # configure driver to rotate screen 90 degrees 39 | tft.init() # initialize display 40 | 41 | height = tft.height() # height of display in pixels 42 | width = tft.width() # width if display in pixels 43 | 44 | tfa = tft_config.TFA # top free area when scrolling 45 | bfa = tft_config.BFA # bottom free area when scrolling 46 | 47 | scroll = 0 # scroll position 48 | wheel = 0 # color wheel position 49 | 50 | tft.vscrdef(tfa, width, bfa) # set scroll area 51 | tft.vscsad(scroll + tfa) # set scroll position 52 | tft.fill(st7789.BLACK) # clear screen 53 | 54 | half = (height >> 1) - 1 # half the height of the dislay 55 | interval = 0 # steps between new points 56 | increment = 0 # increment per step 57 | counter = 1 # step counter, overflow to start 58 | current_y = 0 # current_y value (right point) 59 | last_y = 0 # last_y value (left point) 60 | 61 | # segment offsets 62 | x_offsets = [x * (width // 8) -1 for x in range(2,9)] 63 | 64 | while True: 65 | # when the counter exceeds the interval, save current_y to last_y, 66 | # choose a new random value for current_y between 0 and 1/2 the 67 | # height of the display, choose a new random interval then reset 68 | # the counter to 0 69 | 70 | if counter > interval: 71 | last_y = current_y 72 | current_y = random.randint(0, half) 73 | counter = 0 74 | interval = random.randint(10, 100) 75 | increment = 1 / interval 76 | 77 | # clear the first column of the display and scroll it 78 | tft.vline(scroll, 0, height, st7789.BLACK) 79 | tft.vscsad(scroll + tfa) 80 | 81 | # get the next point between last_y and current_y 82 | tween = int(between(last_y, current_y, counter * increment)) 83 | 84 | # draw mirrored pixels across the display at the offsets using the color_wheel effect 85 | for i, x_offset in enumerate(x_offsets): 86 | tft.pixel((scroll + x_offset) % width, half + tween, color_wheel(wheel+(i<<2))) 87 | tft.pixel((scroll + x_offset) % width, half - tween, color_wheel(wheel+(i<<2))) 88 | 89 | # increment scroll, counter, and wheel 90 | scroll = (scroll + 1) % width 91 | wheel = (wheel + 1) % 256 92 | counter += 1 93 | 94 | # pause to slow down scrolling 95 | utime.sleep(0.0025) 96 | 97 | finally: 98 | tft.deinit() 99 | 100 | main() 101 | -------------------------------------------------------------------------------- /examples/font_decode.py: -------------------------------------------------------------------------------- 1 | """Example showing how to deocode glyph bitmaps from a font module""" 2 | 3 | import proverbs_font as font 4 | 5 | text = "师父领进门,修行在个人" 6 | 7 | def get_bitmap_offset(index): 8 | """ Return the bitmap bit offset for the glpyh at `index`""" 9 | offset_first = index * font.OFFSET_WIDTH 10 | offset = 0 11 | for offset_byte in range(font.OFFSET_WIDTH): 12 | offset = (offset << 8) + font.OFFSETS[offset_first + offset_byte] 13 | return offset 14 | 15 | def get_pixel_color(bit): 16 | """Return the color of the pixel starting at `bit` comprised of `font.BPP` bits""" 17 | pixel_color = 0 18 | for _ in range(font.BPP): 19 | pixel_color = (pixel_color << 1) | font.BITMAPS[bit // 8] & 1 << (7 - (bit % 8)) 20 | bit += 1 21 | 22 | return pixel_color 23 | 24 | # Draw the string `text` one glyph at a time 25 | for glyph in text: 26 | print({glyph}) 27 | glyph_index = font.MAP.index(glyph) 28 | glyph_width = font.WIDTHS[glyph_index] 29 | glyph_bitmap_data = get_bitmap_offset(glyph_index) 30 | for _ in range(font.HEIGHT): 31 | for _ in range(glyph_width): 32 | color = get_pixel_color(glyph_bitmap_data) 33 | print('#' if color else ' ', end='') 34 | glyph_bitmap_data += font.BPP 35 | print() 36 | print("\n") 37 | -------------------------------------------------------------------------------- /examples/hello.py: -------------------------------------------------------------------------------- 1 | """ 2 | hello.py 3 | 4 | Writes "Hello!" in random colors at random locations on the display. 5 | 6 | """ 7 | 8 | import random 9 | import utime 10 | import st7789 11 | import tft_config 12 | import vga1_bold_16x32 as font 13 | 14 | tft = tft_config.config(0, buffer_size=64*64*2) 15 | 16 | def center(text): 17 | length = len(text) 18 | tft.text( 19 | font, 20 | text, 21 | tft.width() // 2 - length // 2 * font.WIDTH, 22 | tft.height() // 2 - font.HEIGHT, 23 | st7789.WHITE, 24 | st7789.RED) 25 | 26 | def main(): 27 | try: 28 | tft.init() 29 | 30 | tft.fill(st7789.RED) 31 | center("Hello!") 32 | utime.sleep(2) 33 | tft.fill(st7789.BLACK) 34 | while True: 35 | for rotation in range(4): 36 | start = utime.ticks_ms() 37 | tft.rotation(rotation) 38 | tft.fill(0) 39 | col_max = tft.width() - font.WIDTH*6 40 | row_max = tft.height() - font.HEIGHT 41 | 42 | for _ in range(128): 43 | tft.text( 44 | font, 45 | "Hello!", 46 | random.randint(0, col_max), 47 | random.randint(0, row_max), 48 | st7789.color565( 49 | random.getrandbits(8), 50 | random.getrandbits(8), 51 | random.getrandbits(8)), 52 | st7789.color565( 53 | random.getrandbits(8), 54 | random.getrandbits(8), 55 | random.getrandbits(8))) 56 | print(f"CPS: {1000 / (utime.ticks_ms() - start)}") 57 | 58 | finally: 59 | tft.deinit() 60 | 61 | main() 62 | -------------------------------------------------------------------------------- /examples/hershey.py: -------------------------------------------------------------------------------- 1 | """ 2 | hershey.py 3 | 4 | Demo program that draws greetings on display cycling thru hershey fonts and colors. 5 | 6 | """ 7 | 8 | import random 9 | import utime 10 | import st7789 11 | import tft_config 12 | 13 | tft = tft_config.config(0, options=st7789.WRAP_V) 14 | 15 | # Load several frozen fonts from flash 16 | 17 | import greeks 18 | import italicc 19 | import italiccs 20 | import meteo 21 | import romanc 22 | import romancs 23 | import romand 24 | import romanp 25 | import romans 26 | import scriptc 27 | import scripts 28 | 29 | 30 | def cycle(p): 31 | """return the next item in a list""" 32 | try: 33 | len(p) 34 | except TypeError: 35 | cache = [] 36 | for i in p: 37 | yield i 38 | cache.append(i) 39 | 40 | p = cache 41 | while p: 42 | yield from p 43 | 44 | 45 | # Create a cycle of colors 46 | COLORS = cycle([0xe000, 0xece0, 0xe7e0, 0x5e0, 0x00d3, 0x7030]) 47 | 48 | # List Hershey fonts 49 | FONT = [greeks, italicc, italiccs, meteo, romanc, romancs, romand, romanp, romans, scriptc, scripts] 50 | 51 | # Create a cycle of tuples consisting of a FONT[] and the HEIGHT of the next FONT[] in the cycle 52 | FONTS = cycle([ 53 | (font, FONT[(i + 1) % len(FONT)].HEIGHT) 54 | for i, font in enumerate(FONT)]) 55 | 56 | # Greetings 57 | GREETING = [ 58 | "Ahoy", "Bonjour", "Bonsoir", "Buenos Dias", "Buenas tardes", "Buenas Noches", "Ciao", "Dude", 59 | "Good Morning", "Good Day", "Good Evening", "Hello", "Hey", "Hi", "Hiya", "Hola", "How Are You", 60 | "How Goes It", "Howdy", "How you doing", "Konnichiwa","Salut", "Shalom", "Welcome", "What's Up", 61 | 'Yo!'] 62 | 63 | # Create a cycle of tuples consisting of a list of words from a GREETING, the number of spaces+1 64 | # in the that GREETING, and the number of spaces+1 in the next GREETING of the cycle 65 | GREETINGS = cycle([ 66 | (greeting.split(), greeting.count(' ')+1, GREETING[(i + 1) % len(GREETING)].count(' ')+1) 67 | for i, greeting in enumerate(GREETING)]) 68 | 69 | 70 | def main(): 71 | """Scroll greetings on the display cycling thru Hershey fonts and colors""" 72 | 73 | try: 74 | tft.init() 75 | tft.fill(st7789.BLACK) 76 | 77 | height = tft.height() 78 | width = tft.width() 79 | 80 | # Set up scrolling area 81 | tfa = tft_config.TFA 82 | bfa = tft_config.BFA 83 | tft.vscrdef(tfa, height, bfa) 84 | 85 | scroll = 0 86 | to_scroll = 0 87 | 88 | while True: 89 | 90 | # if we have scrolled high enough for the next greeting 91 | if to_scroll == 0: 92 | font = next(FONTS) # get the next font 93 | greeting = next(GREETINGS) # get the next greeting 94 | color = next(COLORS) # get the next color 95 | lines = greeting[2] # number of lines in the greeting 96 | to_scroll = lines * font[1] + 8 # number of rows to scroll 97 | 98 | # draw each line of the greeting 99 | for i, word in enumerate(greeting[0][::-1]): 100 | word_len = tft.draw_len(font[0], word) # width in pixels 101 | col = 0 if word_len > width else (width//2 - word_len//2) # column to center 102 | row = (scroll + height - ((i + 1) * font[0].HEIGHT) % height) # row to draw 103 | tft.draw(font[0], word, col, row, color) # draw the word 104 | 105 | tft.fill_rect(0, scroll, width, 1, st7789.BLACK) # clear the top line 106 | tft.vscsad(scroll+tfa) # scroll the display 107 | scroll = (scroll+1) % height # update the scroll position 108 | to_scroll -= 1 # update rows left to scroll 109 | utime.sleep(0.02) # stop and smell the roses 110 | 111 | finally: 112 | tft.deinit() 113 | 114 | main() 115 | -------------------------------------------------------------------------------- /examples/jpg/bigbuckbunny-128x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/jpg/bigbuckbunny-128x128.jpg -------------------------------------------------------------------------------- /examples/jpg/bigbuckbunny-160x128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/jpg/bigbuckbunny-160x128.jpg -------------------------------------------------------------------------------- /examples/jpg/bigbuckbunny-240x135.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/jpg/bigbuckbunny-240x135.jpg -------------------------------------------------------------------------------- /examples/jpg/bigbuckbunny-240x240.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/jpg/bigbuckbunny-240x240.jpg -------------------------------------------------------------------------------- /examples/jpg/bigbuckbunny-320x170.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/jpg/bigbuckbunny-320x170.jpg -------------------------------------------------------------------------------- /examples/jpg/bigbuckbunny-320x240.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/jpg/bigbuckbunny-320x240.jpg -------------------------------------------------------------------------------- /examples/jpg/jpg.py: -------------------------------------------------------------------------------- 1 | """ 2 | jpg.py 3 | 4 | Draw a full screen jpg using the slower but less memory intensive method of blitting 5 | each Minimum Coded Unit (MCU) block. Usually 8×8pixels but can be other multiples of 8. 6 | 7 | bigbuckbunny.jpg (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org 8 | """ 9 | 10 | import random 11 | import st7789 12 | import tft_config 13 | 14 | tft = tft_config.config(1) 15 | 16 | def main(): 17 | ''' 18 | Decode and draw jpg on display 19 | ''' 20 | 21 | try: 22 | tft.init() 23 | tft.jpg(f'bigbuckbunny-{tft.width()}x{tft.height()}.jpg', 0, 0, st7789.SLOW) 24 | 25 | finally: 26 | tft.deinit() 27 | 28 | main() 29 | -------------------------------------------------------------------------------- /examples/mono_fonts/mono_fonts.py: -------------------------------------------------------------------------------- 1 | """ 2 | mono_fonts.py test for monofont2bitmap converter and bitmap method. This is the older method of 3 | converting monofonts to bitmaps. See the newer method in prop_fonts/chango.py that works with 4 | mono and proportional fonts using the write method. 5 | """ 6 | 7 | import time 8 | import st7789 9 | import tft_config 10 | 11 | import inconsolata_16 as font_16 12 | import inconsolata_32 as font_32 13 | import inconsolata_64 as font_64 14 | 15 | tft = tft_config.config(1, buffer_size=66*32*2) 16 | 17 | def display_font(font, fast): 18 | tft.fill(st7789.BLUE) 19 | column = 0 20 | row = 0 21 | for char in font.MAP: 22 | tft.bitmap(font, column, row, font.MAP.index(char)) 23 | column += font.WIDTH 24 | if column >= tft.width() - font.WIDTH: 25 | row += font.HEIGHT 26 | column = 0 27 | 28 | if row > tft.height() - font.HEIGHT: 29 | row = 0 30 | 31 | if not fast: 32 | time.sleep(0.05) 33 | 34 | 35 | def main(): 36 | fast = False 37 | 38 | try: 39 | tft.init() 40 | 41 | while True: 42 | for font in [font_16, font_32, font_64]: 43 | display_font(font, fast) 44 | 45 | fast = not fast 46 | 47 | finally: 48 | tft.deinit() 49 | 50 | main() 51 | -------------------------------------------------------------------------------- /examples/noto_fonts.py: -------------------------------------------------------------------------------- 1 | """ 2 | noto_fonts Writes the names of three Noto fonts centered on the display 3 | using the font. The fonts were converted from True Type fonts using 4 | the font2bitmap utility. 5 | """ 6 | 7 | import st7789 8 | import tft_config 9 | import NotoSans_32 as noto_sans 10 | import NotoSerif_32 as noto_serif 11 | import NotoSansMono_32 as noto_mono 12 | 13 | 14 | tft = tft_config.config(1, buffer_size=16*32*2) 15 | 16 | 17 | def center(font, s, row, color=st7789.WHITE): 18 | screen = tft.width() # get screen width 19 | width = tft.write_len(font, s) # get the width of the string 20 | col = tft.width() // 2 - width // 2 if width and width < screen else 0 21 | tft.write(font, s, col, row, color) # and write the string 22 | 23 | 24 | def main(): 25 | try: 26 | # init display 27 | tft.init() 28 | tft.fill(st7789.BLACK) 29 | 30 | # center the name of the first font, using the font 31 | row = 16 32 | center(noto_sans, "NotoSans", row, st7789.RED) 33 | row += noto_sans.HEIGHT 34 | 35 | # center the name of the second font, using the font 36 | center(noto_serif, "NotoSerif", row, st7789.GREEN) 37 | row += noto_serif.HEIGHT 38 | 39 | # center the name of the third font, using the font 40 | center(noto_mono, "NotoSansMono", row, st7789.BLUE) 41 | row += noto_mono.HEIGHT 42 | 43 | finally: 44 | tft.deinit() 45 | 46 | main() 47 | -------------------------------------------------------------------------------- /examples/png/alien.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/png/alien.png -------------------------------------------------------------------------------- /examples/png/alien.py: -------------------------------------------------------------------------------- 1 | ''' 2 | alien.py 3 | 4 | Randomly draw alien.png with alpha-channel masking 5 | 6 | The alien.png is from the Erik Flowers Weather Icons available from 7 | https://github.com/erikflowers/weather-icons and is licensed under 8 | SIL OFL 1.1 9 | 10 | ''' 11 | 12 | import gc 13 | import random 14 | import tft_config 15 | import st7789 16 | 17 | gc.enable() 18 | gc.collect() 19 | 20 | 21 | def main(): 22 | ''' 23 | Decode and draw png on display 24 | ''' 25 | 26 | try: 27 | tft = tft_config.config(1, buffer_size=30*2) 28 | 29 | # enable display and clear screen 30 | tft.init() 31 | 32 | # display png in random locations 33 | while True: 34 | tft.rotation(random.randint(0, 4)) 35 | tft.png( 36 | "alien.png", 37 | random.randint(0, tft.width() - 63), 38 | random.randint(0, tft.height() - 63), 39 | True) 40 | 41 | finally: 42 | tft.deinit() 43 | 44 | main() 45 | -------------------------------------------------------------------------------- /examples/proverbs/NotoSansSC-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/proverbs/NotoSansSC-Regular.otf -------------------------------------------------------------------------------- /examples/proverbs/makefont: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ../../../utils/font2bitmap.py \ 4 | -s "万事起头难。熟能生巧。冰冻三尺,非一日之寒。三个臭皮匠,胜过诸葛亮。今日事,今日毕。师父领进门,修行在个人。一口吃不成胖子。欲速则不达。百闻不如一见。不入虎穴,焉得虎子。" \ 5 | NotoSansSC-Regular.otf 30 >proverbs_font.py 6 | -------------------------------------------------------------------------------- /examples/proverbs/proverbs.py: -------------------------------------------------------------------------------- 1 | """ 2 | proverbs.py - Displays what I hope are chinese proverbs in simplified chinese to test UTF-8 3 | font support. 4 | """ 5 | 6 | import utime 7 | import st7789 8 | import tft_config 9 | import proverbs_font as font 10 | 11 | 12 | tft = tft_config.config(1) 13 | 14 | 15 | def color_wheel(WheelPos): 16 | """returns a 565 color from the given position of the color wheel""" 17 | WheelPos = (255 - WheelPos) % 255 18 | 19 | if WheelPos < 85: 20 | return st7789.color565(255 - WheelPos * 3, 0, WheelPos * 3) 21 | 22 | if WheelPos < 170: 23 | WheelPos -= 85 24 | return st7789.color565(0, WheelPos * 3, 255 - WheelPos * 3) 25 | 26 | WheelPos -= 170 27 | return st7789.color565(WheelPos * 3, 255 - WheelPos * 3, 0) 28 | 29 | def main(): 30 | 31 | proverbs = [ 32 | "万事起头难", 33 | "熟能生巧", 34 | "冰冻三尺,非一日之寒", 35 | "三个臭皮匠,胜过诸葛亮", 36 | "今日事,今日毕", 37 | "师父领进门,修行在个人", 38 | "一口吃不成胖子", 39 | "欲速则不达", 40 | "百闻不如一见", 41 | "不入虎穴,焉得虎子"] 42 | 43 | try: 44 | # initialize display 45 | tft.init() 46 | line_height = font.HEIGHT+8 47 | half_height = tft.height() // 2 48 | half_width = tft.width() // 2 49 | wheel = 0 50 | 51 | tft.fill(st7789.BLACK) 52 | 53 | while True: 54 | for proverb in proverbs: 55 | proverb_lines = proverb.split(',') 56 | half_lines_height = len(proverb_lines) * line_height // 2 57 | 58 | tft.fill(st7789.BLACK) 59 | 60 | for count, proverb_line in enumerate(proverb_lines): 61 | half_length = tft.write_len(font, proverb_line) // 2 62 | 63 | tft.write( 64 | font, 65 | proverb_line, 66 | half_width - half_length, 67 | half_height - half_lines_height + count * line_height, 68 | color_wheel(wheel)) 69 | 70 | wheel = (wheel + 5) % 256 71 | 72 | # pause to slow down scrolling 73 | utime.sleep(5) 74 | 75 | finally: 76 | tft.deinit() 77 | 78 | main() 79 | -------------------------------------------------------------------------------- /examples/scroll.py: -------------------------------------------------------------------------------- 1 | """ 2 | scroll.py 3 | 4 | Smoothly scroll all characters of a font up the display. 5 | Fonts heights must be even multiples of the screen height 6 | (i.e. 8 or 16 pixels high). 7 | """ 8 | 9 | import utime 10 | import st7789 11 | import tft_config 12 | import vga1_bold_16x16 as font 13 | 14 | 15 | tft = tft_config.config(0) 16 | 17 | 18 | def cycle(p): 19 | try: 20 | len(p) 21 | except TypeError: 22 | cache = [] 23 | for i in p: 24 | yield i 25 | cache.append(i) 26 | p = cache 27 | while p: 28 | yield from p 29 | 30 | 31 | def main(): 32 | 33 | try: 34 | tft.init() 35 | 36 | colors = cycle([0xe000, 0xece0, 0xe7e0, 0x5e0, 0x00d3, 0x7030]) 37 | foreground = next(colors) 38 | background = st7789.BLACK 39 | 40 | tft.fill(background) 41 | utime.sleep(1) 42 | 43 | height = tft.height() 44 | width = tft.width() 45 | last_line = height - font.HEIGHT 46 | 47 | tfa = tft_config.TFA # top free area 48 | bfa = tft_config.BFA # bottom free area 49 | 50 | tft.vscrdef(tfa, height, bfa) 51 | 52 | scroll = 0 53 | character = font.FIRST 54 | 55 | while True: 56 | # clear top line before scrolling off display 57 | tft.fill_rect(0, scroll, width, 1, background) 58 | 59 | # Write new line when we have scrolled the height of a character 60 | if scroll % font.HEIGHT == 0: 61 | line = (scroll + last_line) % height 62 | 63 | # write character hex value as a string 64 | tft.text( 65 | font, 66 | 'x{:02x}'.format(character), 67 | 16, 68 | line, 69 | foreground, 70 | background) 71 | 72 | # write character using a integer (could be > 0x7f) 73 | tft.text( 74 | font, 75 | character, 76 | 90, 77 | line, 78 | foreground, 79 | background) 80 | 81 | # change color for next line 82 | foreground = next(colors) 83 | 84 | # next character with rollover at 256 85 | character += 1 86 | if character > font.LAST: 87 | character = font.FIRST 88 | 89 | # scroll the screen up 1 row 90 | tft.vscsad(scroll+tfa) 91 | scroll += 1 92 | scroll %= height 93 | 94 | utime.sleep(0.01) 95 | 96 | finally: 97 | tft.deinit() 98 | 99 | main() 100 | -------------------------------------------------------------------------------- /examples/tft_buttons.py: -------------------------------------------------------------------------------- 1 | # input pins for buttons: you will need to change these to match your wiring 2 | 3 | from machine import Pin 4 | 5 | class Buttons(): 6 | def __init__(self): 7 | self.name = "t-display-s3" 8 | self.left = Pin(0, Pin.IN) 9 | self.right = Pin(14, Pin.IN) 10 | 11 | # need more buttons for roids.py 12 | self.fire = 0 13 | self.thrust = 0 14 | self.hyper = 0 15 | -------------------------------------------------------------------------------- /examples/tft_config.py: -------------------------------------------------------------------------------- 1 | """ LilyGo T-DISPLAY-S3 170x320 ST7789 display """ 2 | 3 | from machine import Pin, SPI, freq 4 | import st7789 5 | 6 | freq(240000000) # 240mhz clock 7 | 8 | TFA = 0 9 | BFA = 0 10 | 11 | def config(rotation=0, buffer_size=0, options=0): 12 | LCD_POWER = Pin(15, Pin.OUT) 13 | LCD_POWER.value(1) 14 | 15 | return st7789.ST7789( 16 | Pin(48, Pin.OUT), 17 | Pin(47, Pin.OUT), 18 | Pin(46, Pin.OUT), 19 | Pin(45, Pin.OUT), 20 | Pin(42, Pin.OUT), 21 | Pin(41, Pin.OUT), 22 | Pin(40, Pin.OUT), 23 | Pin(39, Pin.OUT), 24 | Pin(8, Pin.OUT), 25 | Pin(9, Pin.OUT), 26 | 170, 27 | 320, 28 | reset=Pin(5, Pin.OUT), 29 | cs=Pin(6, Pin.OUT), 30 | dc=Pin(7, Pin.OUT), 31 | backlight=Pin(38, Pin.OUT), 32 | rotation=rotation, 33 | options=options, 34 | buffer_size= buffer_size) 35 | -------------------------------------------------------------------------------- /examples/tiny_toasters/tiny_toasters.py: -------------------------------------------------------------------------------- 1 | """ 2 | tiny_toasters.py - Flying Tiny Toasters for smaller displays (like the ST7735) 3 | 4 | Uses spritesheet from CircuitPython_Flying_Toasters pendant project 5 | https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 6 | 7 | Convert spritesheet bmp to tft.bitmap() method compatible python module using: 8 | python3 ./sprites2bitmap.py ttoasters.bmp 32 32 4 > ttoast_bitmaps.py 9 | 10 | """ 11 | 12 | import gc 13 | import time 14 | import random 15 | import st7789 16 | import tft_config 17 | import ttoast_bitmaps as toast_bitmaps 18 | 19 | TOASTER_FRAMES = [0, 1, 2, 3] 20 | TOAST_FRAMES = [4] 21 | 22 | def collide(a_col, a_row, a_width, a_height, b_col, b_row, b_width, b_height): 23 | '''return true if two rectangles overlap''' 24 | return (a_col + a_width >= b_col and a_col <= b_col + b_width 25 | and a_row + a_height >= b_row and a_row <= b_row + b_height) 26 | 27 | def random_start(tft, sprites, bitmaps, num): 28 | ''' 29 | Return a random location along the top or right of the screen, if that location would overlaps 30 | with another sprite return (0,0). This allows the other sprites to keep moving giving the next 31 | random_start a better chance to avoid a collision. 32 | 33 | ''' 34 | # 50/50 chance to try along the top/right half or along the right/top half of the screen 35 | if random.getrandbits(1): 36 | row = 1 37 | col = random.randint(bitmaps.WIDTH//2, tft.width()-bitmaps.WIDTH) 38 | else: 39 | col = tft.width() - bitmaps.WIDTH 40 | row = random.randint(1, tft.height() // 2) 41 | 42 | if any(collide( 43 | col, row, bitmaps.WIDTH, bitmaps.HEIGHT, 44 | sprite.col, sprite.row, sprite.width, sprite.height) 45 | for sprite in sprites if num != sprite.num): 46 | 47 | col = 0 48 | row = 0 49 | 50 | return (col, row) 51 | 52 | def main(): 53 | 54 | class Toast(): 55 | ''' 56 | Toast class to keep track of toaster and toast sprites 57 | ''' 58 | def __init__(self, sprites, bitmaps, frames): 59 | '''create new sprite in random location that does not overlap other sprites''' 60 | self.num = len(sprites) 61 | self.bitmaps = bitmaps 62 | self.frames = frames 63 | self.steps = len(frames) 64 | self.col, self.row = random_start(tft, sprites, bitmaps, self.num) 65 | self.width = bitmaps.WIDTH 66 | self.height = bitmaps.HEIGHT 67 | self.last_col = self.col 68 | self.last_row = self.row 69 | self.step = random.randint(0, self.steps) 70 | self.dir_col = -random.randint(2, 5) 71 | self.dir_row = 2 72 | self.prev_dir_col = self.dir_col 73 | self.prev_dir_row = self.dir_row 74 | self.iceberg = 0 75 | 76 | def clear(self): 77 | '''clear above and behind sprite''' 78 | tft.fill_rect( 79 | self.col, self.row-1, self.width, self.dir_row+1, 80 | st7789.BLACK) 81 | 82 | tft.fill_rect( 83 | self.col+self.width+self.dir_col, self.row, 84 | -self.dir_col, self.height, st7789.BLACK) 85 | 86 | def erase(self): 87 | '''erase last postion of sprite''' 88 | tft.fill_rect( 89 | self.last_col, self.last_row, self.width, self.height, st7789.BLACK) 90 | 91 | def move(self, sprites): 92 | '''step frame and move sprite''' 93 | 94 | if self.steps: 95 | self.step = (self.step + 1) % self.steps 96 | 97 | self.last_col = self.col 98 | self.last_row = self.row 99 | new_col = self.col + self.dir_col 100 | new_row = self.row + self.dir_row 101 | 102 | # if new location collides with another sprite, change direction for 32 frames 103 | 104 | for sprite in sprites: 105 | if ( 106 | self.num != sprite.num 107 | and collide( 108 | new_col, new_row, self.width, self.height, 109 | sprite.col, sprite.row, sprite.width, sprite.height, 110 | ) 111 | and (self.col > sprite.col)): 112 | 113 | self.iceberg = 32 114 | self.dir_col = -1 115 | self.dir_row = 3 116 | new_col = self.col + self.dir_col 117 | new_row = self.row + self.dir_row 118 | 119 | self.col = new_col 120 | self.row = new_row 121 | 122 | # if new location touches edge of screen, erase then set new start location 123 | if self.col <= 0 or self.row > tft.height() - self.height: 124 | self.erase() 125 | self.dir_col = -random.randint(2, 5) 126 | self.dir_row = 2 127 | self.col, self.row = random_start(tft, sprites, self.bitmaps, self.num) 128 | 129 | # Track post collision direction change 130 | if self.iceberg: 131 | self.iceberg -= 1 132 | if self.iceberg == 1: 133 | self.dir_col = self.prev_dir_col 134 | self.dir_row = self.prev_dir_row 135 | 136 | def draw(self): 137 | '''if the location is not 0,0 draw current frame of sprite at it's location''' 138 | if self.col and self.row: 139 | tft.bitmap(self.bitmaps, self.col, self.row, self.frames[self.step]) 140 | 141 | 142 | try: 143 | tft = tft_config.config(1, buffer_size=64*62*2) # configure display driver 144 | 145 | # init and clear screen 146 | tft.init() 147 | tft.fill(st7789.BLACK) 148 | 149 | # create toast spites and set animation frames 150 | sprites = [] 151 | sprites.append(Toast(sprites, toast_bitmaps, TOAST_FRAMES)) 152 | sprites.append(Toast(sprites, toast_bitmaps, TOASTER_FRAMES)) 153 | sprites.append(Toast(sprites, toast_bitmaps, TOASTER_FRAMES)) 154 | 155 | # move and draw sprites 156 | 157 | while True: 158 | for sprite in sprites: 159 | sprite.clear() 160 | sprite.move(sprites) 161 | sprite.draw() 162 | 163 | gc.collect() 164 | time.sleep(0.05) 165 | 166 | finally: 167 | tft.deinit() 168 | 169 | 170 | main() 171 | -------------------------------------------------------------------------------- /examples/tiny_toasters/ttoasters.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/tiny_toasters/ttoasters.bmp -------------------------------------------------------------------------------- /examples/toasters/maketoast: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # grab sprites from spritesheet using ImageMagick and convert to bitmap format. 5 | # 6 | # spritesheet from CircuitPython_Flying_Toasters 7 | # https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 8 | # 9 | 10 | convert toasters.bmp -crop 64x64+64+0 t1.png 11 | convert toasters.bmp -crop 64x64+128+0 t2.png 12 | convert toasters.bmp -crop 64x64+192+0 t3.png 13 | convert toasters.bmp -crop 64x64+256+0 t4.png 14 | convert toasters.bmp -crop 64x64+320+0 t5.png 15 | 16 | # use 3 bits per pixel / 8 colors 17 | 18 | ../../utils/imgtobitmap.py t1.png 3 >t1.py 19 | ../../utils/imgtobitmap.py t2.png 3 >t2.py 20 | ../../utils/imgtobitmap.py t3.png 3 >t3.py 21 | ../../utils/imgtobitmap.py t4.png 3 >t4.py 22 | ../../utils/imgtobitmap.py t5.png 3 >t5.py 23 | -------------------------------------------------------------------------------- /examples/toasters/t1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters/t1.png -------------------------------------------------------------------------------- /examples/toasters/t2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters/t2.png -------------------------------------------------------------------------------- /examples/toasters/t3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters/t3.png -------------------------------------------------------------------------------- /examples/toasters/t4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters/t4.png -------------------------------------------------------------------------------- /examples/toasters/t5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters/t5.png -------------------------------------------------------------------------------- /examples/toasters/toasters.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters/toasters.bmp -------------------------------------------------------------------------------- /examples/toasters/toasters.py: -------------------------------------------------------------------------------- 1 | """ 2 | toasters.py - Flying Toasters 3 | 4 | Uses spritesheet from CircuitPython_Flying_Toasters pendant project 5 | https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 6 | 7 | Convert spritesheet bmp to tft.bitmap() method compatible python module using: 8 | python3 ./sprites2bitmap.py toasters.bmp 64 64 4 > toast_bitmaps.py 9 | 10 | """ 11 | 12 | import gc 13 | import time 14 | import random 15 | import st7789 16 | import tft_config 17 | import toast_bitmaps 18 | 19 | TOASTER_FRAMES = [0, 1, 2, 3] 20 | TOAST_FRAMES = [4] 21 | 22 | def collide(a_col, a_row, a_width, a_height, b_col, b_row, b_width, b_height): 23 | '''return true if two rectangles overlap''' 24 | return (a_col + a_width >= b_col and a_col <= b_col + b_width 25 | and a_row + a_height >= b_row and a_row <= b_row + b_height) 26 | 27 | def random_start(tft, sprites, bitmaps, num): 28 | ''' 29 | Return a random location along the top or right of the screen, if that location would overlaps 30 | with another sprite return (0,0). This allows the other sprites to keep moving giving the next 31 | random_start a better chance to avoid a collision. 32 | 33 | ''' 34 | # 50/50 chance to try along the top/right half or along the right/top half of the screen 35 | if random.getrandbits(1): 36 | row = 1 37 | col = random.randint(bitmaps.WIDTH//2, tft.width()-bitmaps.WIDTH) 38 | else: 39 | col = tft.width() - bitmaps.WIDTH 40 | row = random.randint(1, tft.height() // 2) 41 | 42 | if any(collide( 43 | col, row, bitmaps.WIDTH, bitmaps.HEIGHT, 44 | sprite.col, sprite.row, sprite.width, sprite.height) 45 | for sprite in sprites if num != sprite.num): 46 | 47 | col = 0 48 | row = 0 49 | 50 | return (col, row) 51 | 52 | def main(): 53 | 54 | class Toast(): 55 | ''' 56 | Toast class to keep track of toaster and toast sprites 57 | ''' 58 | def __init__(self, sprites, bitmaps, frames): 59 | '''create new sprite in random location that does not overlap other sprites''' 60 | self.num = len(sprites) 61 | self.bitmaps = bitmaps 62 | self.frames = frames 63 | self.steps = len(frames) 64 | self.col, self.row = random_start(tft, sprites, bitmaps, self.num) 65 | self.width = bitmaps.WIDTH 66 | self.height = bitmaps.HEIGHT 67 | self.last_col = self.col 68 | self.last_row = self.row 69 | self.step = random.randint(0, self.steps) 70 | self.dir_col = -random.randint(2, 5) 71 | self.dir_row = 2 72 | self.prev_dir_col = self.dir_col 73 | self.prev_dir_row = self.dir_row 74 | self.iceberg = 0 75 | 76 | def clear(self): 77 | '''clear above and behind sprite''' 78 | tft.fill_rect( 79 | self.col, self.row-1, self.width, self.dir_row+1, 80 | st7789.BLACK) 81 | 82 | tft.fill_rect( 83 | self.col+self.width+self.dir_col, self.row, 84 | -self.dir_col, self.height, st7789.BLACK) 85 | 86 | def erase(self): 87 | '''erase last postion of sprite''' 88 | tft.fill_rect( 89 | self.last_col, self.last_row, self.width, self.height, st7789.BLACK) 90 | 91 | def move(self, sprites): 92 | '''step frame and move sprite''' 93 | 94 | if self.steps: 95 | self.step = (self.step + 1) % self.steps 96 | 97 | self.last_col = self.col 98 | self.last_row = self.row 99 | new_col = self.col + self.dir_col 100 | new_row = self.row + self.dir_row 101 | 102 | # if new location collides with another sprite, change direction for 32 frames 103 | 104 | for sprite in sprites: 105 | if ( 106 | self.num != sprite.num 107 | and collide( 108 | new_col, new_row, self.width, self.height, 109 | sprite.col, sprite.row, sprite.width, sprite.height, 110 | ) 111 | and (self.col > sprite.col)): 112 | 113 | self.iceberg = 32 114 | self.dir_col = -1 115 | self.dir_row = 3 116 | new_col = self.col + self.dir_col 117 | new_row = self.row + self.dir_row 118 | 119 | self.col = new_col 120 | self.row = new_row 121 | 122 | # if new location touches edge of screen, erase then set new start location 123 | if self.col <= 0 or self.row > tft.height() - self.height: 124 | self.erase() 125 | self.dir_col = -random.randint(2, 5) 126 | self.dir_row = 2 127 | self.col, self.row = random_start(tft, sprites, self.bitmaps, self.num) 128 | 129 | # Track post collision direction change 130 | if self.iceberg: 131 | self.iceberg -= 1 132 | if self.iceberg == 1: 133 | self.dir_col = self.prev_dir_col 134 | self.dir_row = self.prev_dir_row 135 | 136 | def draw(self): 137 | '''if the location is not 0,0 draw current frame of sprite at it's location''' 138 | if self.col and self.row: 139 | tft.bitmap(self.bitmaps, self.col, self.row, self.frames[self.step]) 140 | 141 | try: 142 | tft = tft_config.config(1, buffer_size=64*62*2) # configure display driver 143 | 144 | # init and clear screen 145 | tft.init() 146 | tft.fill(st7789.BLACK) 147 | 148 | # create toast spites and set animation frames 149 | sprites = [] 150 | sprites.append(Toast(sprites, toast_bitmaps, TOAST_FRAMES)) 151 | sprites.append(Toast(sprites, toast_bitmaps, TOASTER_FRAMES)) 152 | sprites.append(Toast(sprites, toast_bitmaps, TOASTER_FRAMES)) 153 | 154 | # move and draw sprites 155 | 156 | while True: 157 | for sprite in sprites: 158 | sprite.clear() 159 | sprite.move(sprites) 160 | sprite.draw() 161 | 162 | gc.collect() 163 | time.sleep(0.01) 164 | 165 | finally: 166 | tft.deinit() 167 | 168 | main() 169 | -------------------------------------------------------------------------------- /examples/toasters_jpg/toaster.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/toasters_jpg/toaster.jpg -------------------------------------------------------------------------------- /examples/toasters_jpg/toasters_jpg.py: -------------------------------------------------------------------------------- 1 | """ 2 | toasters_jpg.py 3 | 4 | An example using a jpg sprite map to draw sprites on T-Display. This is an older version of the 5 | toasters.py and tiny_toasters example. It uses the jpg_decode() method to grab a bitmap of each 6 | sprite from the toaster.jpg sprite sheet. 7 | 8 | youtube video: https://youtu.be/0uWsjKQmCpU 9 | 10 | spritesheet from CircuitPython_Flying_Toasters 11 | https://learn.adafruit.com/circuitpython-sprite-animation-pendant-mario-clouds-flying-toasters 12 | """ 13 | 14 | import time 15 | import random 16 | from machine import Pin, SPI 17 | import st7789 18 | 19 | # 20 | # Select a config module for your display 21 | # 22 | 23 | # Not suitable for esp32_7735_128 due to resolution 24 | # Not suitable for esp32_7735_160 due to resolution 25 | # import tdisplay as Driver 26 | # import twatch_2020_v2 as Driver 27 | # import ws_pico_114 as Driver 28 | # import ws_pico_13 as Driver 29 | # import ws_pico_2 as Driver 30 | import tdisplay_rp2040 as Driver 31 | 32 | tft = Driver.config(0) 33 | 34 | class toast(): 35 | ''' 36 | toast class to keep track of a sprites locaton and step 37 | ''' 38 | 39 | def __init__(self, sprites, x, y): 40 | self.sprites = sprites 41 | self.steps = len(sprites) 42 | self.x = x 43 | self.y = y 44 | self.step = random.randint(0, self.steps-1) 45 | self.speed = random.randint(2, 5) 46 | 47 | def move(self): 48 | if self.x <= 0: 49 | self.speed = random.randint(2, 5) 50 | self.x = 135-64 51 | 52 | self.step += 1 53 | self.step %= self.steps 54 | self.x -= self.speed 55 | 56 | 57 | def main(): 58 | ''' 59 | Draw and move sprite 60 | ''' 61 | 62 | # enable display and clear screen 63 | tft.init() 64 | tft.fill(st7789.BLACK) 65 | 66 | width = 64 67 | height = 64 68 | 69 | # grab each sprite from the toaster.jpg sprite sheet 70 | t1, _, _ = tft.jpg_decode('toaster.jpg', 0, 0, width, height) 71 | t2, _, _ = tft.jpg_decode('toaster.jpg', width, 0, width, height) 72 | t3, _, _ = tft.jpg_decode('toaster.jpg', width*2, 0, width, height) 73 | t4, _, _ = tft.jpg_decode('toaster.jpg', 0, height, width, height) 74 | t5, _, _ = tft.jpg_decode('toaster.jpg', width, height, width, height) 75 | 76 | TOASTERS = [t1, t2, t3, t4] 77 | TOAST = [t5] 78 | 79 | sprites = [ 80 | toast(TOASTERS, tft.width() - width, 0), 81 | toast(TOAST, tft.width() - width * 2, tft.height() // 3), 82 | toast(TOASTERS, tft.width() - width * 4, tft.height() // 3 * 2) 83 | ] 84 | 85 | # move and draw sprites 86 | while True: 87 | for man in sprites: 88 | bitmap = man.sprites[man.step] 89 | tft.fill_rect( 90 | man.x+width-man.speed, 91 | man.y, 92 | man.speed, 93 | height, 94 | st7789.BLACK) 95 | 96 | man.move() 97 | 98 | if man.x > 0: 99 | tft.blit_buffer(bitmap, man.x, man.y, width, height) 100 | else: 101 | tft.fill_rect( 102 | 0, 103 | man.y, 104 | width, 105 | height, 106 | st7789.BLACK) 107 | 108 | time.sleep(0.05) 109 | 110 | 111 | main() 112 | -------------------------------------------------------------------------------- /examples/watch/LibreBaskerville-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/watch/LibreBaskerville-Regular.ttf -------------------------------------------------------------------------------- /examples/watch/create_face_jpg.py: -------------------------------------------------------------------------------- 1 | """ 2 | Create a watch face_{width}x{height}.jpg file for a given width and height. 3 | """ 4 | 5 | import math 6 | from PIL import Image, ImageDraw, ImageFont 7 | 8 | width = 320 # width of the display 9 | height = 170 # height of the display 10 | face = min(width, height) # face is the smaller of the two 11 | ofs = (width - face) // 2 # offset from the left side of the display 12 | 13 | # create an image 14 | out = Image.new("RGB", (width, height), (255, 255, 255)) 15 | 16 | fnt = ImageFont.truetype("./LibreBaskerville-Regular.ttf", 18) # get a font of an appropriate size 17 | d = ImageDraw.Draw(out) # get a drawing context 18 | radius = int(face // 2 * 0.8) # radius of the clock face 19 | cx = int(face // 2) # center x of the clock face 20 | 21 | second = 0 22 | for minute in range(1, 60): 23 | # get the angle of the minute hand 24 | angle = ((minute*math.pi/30)+(second*math.pi/1800)) 25 | cos_a = math.cos(angle) 26 | sin_a = math.sin(angle) 27 | 28 | # x and y coordinates of the outer minute tick 29 | y1 = -cx * cos_a * 0.76 30 | x1 = cx * sin_a * 0.76 31 | 32 | # x and y coordinates of the inner minute tick 33 | y2 = -cx * cos_a * 0.7 34 | x2 = cx * sin_a * 0.7 35 | 36 | # draw the minute tick 37 | d.line([ofs+x1+cx, y1+cx, ofs+x2+cx, y2+cx], width=1, fill="#000000") 38 | 39 | for hour in range(1, 13): 40 | # get the angle of the hour hand 41 | angle = (hour*math.pi/6) 42 | cos_a = math.cos(angle) 43 | sin_a = math.sin(angle) 44 | 45 | # x and y coordinates of the outer hour tick 46 | y1 = -cx * cos_a * 0.76 47 | x1 = cx * sin_a * 0.76 48 | 49 | # x and y coordinates of the inner hour tick 50 | y2 = -cx * cos_a * 0.7 51 | x2 = cx * sin_a * 0.7 52 | 53 | # draw the hour tick 54 | d.line([ofs+x1+cx, y1+cx, ofs+x2+cx, y2+cx], width=5, fill="#ff0000") 55 | 56 | # x and y coordinates of the hour number 57 | y = -cx * cos_a * 0.9 58 | x = cx * sin_a * 0.9 59 | 60 | # draw the hour number in our previously selected font 61 | size = d.textbbox((0, 0), str(hour), font=fnt) 62 | d.text( 63 | (ofs+x+cx-((size[2]+size[0] >> 1)), y+cx-((size[3]+size[1]) >> 1)), 64 | str(hour), 65 | font=fnt, 66 | fill=(0, 0, 0), 67 | align="center") 68 | 69 | # save the face as a jpeg file 70 | out.save(f'face_{width}x{height}.jpg', "JPEG") 71 | # out.show() 72 | -------------------------------------------------------------------------------- /examples/watch/face_320x170.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/examples/watch/face_320x170.jpg -------------------------------------------------------------------------------- /examples/watch/watch.py: -------------------------------------------------------------------------------- 1 | """" 2 | watch.py - Analog Watch Display using jpg for the face and filled polygons for the hands 3 | Requires face_{width}x{height}.jpg in the same directory as this script. See the create_face.py 4 | script for creating a face image for a given sized display. 5 | 6 | Previous version video: https://youtu.be/NItKb6umMc4 7 | """ 8 | 9 | import utime 10 | import math 11 | import st7789 12 | import tft_config 13 | 14 | 15 | tft = tft_config.config(1) 16 | 17 | 18 | def hand_polygon(length, radius): 19 | return [ 20 | (0, 0), 21 | (-radius, radius), 22 | (-radius, int(length * 0.3)), 23 | (-1, length), 24 | (1, length), 25 | (radius, int(length * 0.3)), 26 | (radius, radius), 27 | (0,0) 28 | ] 29 | 30 | 31 | def main(): 32 | ''' 33 | Draw analog watch face and update time 34 | ''' 35 | 36 | try: 37 | # enable display 38 | tft.init() 39 | width = tft.width() 40 | height = tft.height() 41 | radius = min(width, height) # face is the smaller of the two 42 | ofs = (width - radius) // 2 # offset from the left to center the face 43 | center_x = radius // 2 + ofs - 1 # center of the face horizontally 44 | center_y = radius // 2 - 1 # center of the face vertically 45 | 46 | # draw the watch face background 47 | face = "face_{}x{}.jpg".format(width, height) 48 | tft.jpg(face, 0, 0, st7789.SLOW) 49 | 50 | # create the polygons for the hour, minute and second hands 51 | # polygons must be closed convex polygons or bad things(tm) happen. 52 | 53 | second_len = int(radius * 0.65 / 2) 54 | second_poly = hand_polygon(second_len, 2) 55 | 56 | minute_len = int(radius * 0.6 / 2) 57 | minute_poly = hand_polygon(minute_len, 2) 58 | 59 | hour_len = int(radius * 0.5 / 2) 60 | hour_poly = hand_polygon(hour_len, 3) 61 | 62 | # constants for calculating hand angles. 63 | pi_div_6 = math.pi/6 64 | pi_div_30 = math.pi/30 65 | pi_div_360 = math.pi/360 66 | pi_div_1800 = math.pi/1800 67 | pi_div_2160 = math.pi/2160 68 | 69 | # initialize variables for the bounding rectangles for the 70 | # hour, minute and second hands. Calling bounding with True will 71 | # reset the bounds, calling with False will disable bounding 72 | 73 | tft.bounding(True) 74 | hour_bound = tft.bounding(True) 75 | minute_bound = tft.bounding(True) 76 | second_bound = tft.bounding(True) 77 | 78 | while True: 79 | # save the current time in seconds so we can determine when 80 | # when to update the display. 81 | last = utime.time() 82 | 83 | # get the current hour, minute and second 84 | _, _, _, hour, minute, second, _, _ = utime.localtime() 85 | 86 | # constrain hours to 12 hour time 87 | hour %= 12 88 | 89 | # calculate the angle of the hour hand in radians 90 | hour_ang = ( 91 | (hour * pi_div_6) + 92 | (minute * pi_div_360) + 93 | (second * pi_div_2160)) 94 | 95 | # calculate the angle of the minute hand in radians 96 | minute_ang = ((minute*pi_div_30)+(second*pi_div_1800)) 97 | 98 | # calculate the angle of the second hand on radians 99 | second_ang = (second*pi_div_30) 100 | 101 | # erase the bounding area of the last drawn hour hand 102 | x1, y1, x2, y2 = hour_bound 103 | tft.fill_rect(x1, y1, x2, y2, st7789.WHITE) 104 | 105 | # erase the bounding area of the last drawn minute hand 106 | x1, y1, x2, y2 = minute_bound 107 | tft.fill_rect(x1, y1, x2, y2, st7789.WHITE) 108 | 109 | # erase the bounding area of the last drawn second hand 110 | x1, y1, x2, y2 = second_bound 111 | tft.fill_rect(x1, y1, x2, y2, st7789.WHITE) 112 | 113 | # draw the hub after erasing the bounding areas to reduce flickering 114 | tft.fill_circle(center_x, center_y, 5, st7789.BLACK) 115 | 116 | tft.bounding(True) # clear bounding rectangle 117 | 118 | # draw and fill the hour hand polygon rotated to hour_ang 119 | tft.fill_polygon(hour_poly, center_x, center_y, st7789.BLACK, hour_ang) 120 | 121 | # get the bounding rectangle of the hour_polygon as drawn and 122 | # reset the bounding box for the next polygon 123 | hour_bound = tft.bounding(True, True) 124 | 125 | # draw and fill the minute hand polygon rotated to minute_ang 126 | tft.fill_polygon(minute_poly, center_x, center_y, st7789.BLACK, minute_ang) 127 | 128 | # get the bounding rectangle of the minute_polygon as drawn and 129 | # reset the bounding box for the next polygon 130 | minute_bound = tft.bounding(True, True) 131 | 132 | # draw and fill the second hand polygon rotated to second_ang 133 | 134 | tft.fill_polygon(second_poly, center_x, center_y, st7789.RED, second_ang) 135 | 136 | # get the bounding rectangle of the second_polygon as drawn and 137 | # reset the bounding box for the next polygon 138 | second_bound = tft.bounding(True, True) 139 | 140 | # draw the hub again to cover up the second hand 141 | tft.fill_circle(center_x, center_y, 5, st7789.BLACK) 142 | 143 | # wait until the current second changes 144 | while last == utime.time(): 145 | utime.sleep_ms(50) 146 | 147 | finally: 148 | tft.deinit() 149 | 150 | main() 151 | -------------------------------------------------------------------------------- /firmware/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2023 Damien P. George 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- 24 | 25 | Unless specified otherwise (see below), the above license and copyright applies 26 | to all files in this repository. 27 | 28 | Individual files may include additional copyright holders. 29 | 30 | The various ports of MicroPython may include third-party software that is 31 | licensed under different terms. These licenses are summarised in the tree 32 | below, please refer to these files and directories for further license and 33 | copyright information. Note that (L)GPL-licensed code listed below is only 34 | used during the build process and is not part of the compiled source code. 35 | 36 | / (MIT) 37 | /drivers 38 | /cc3100 (BSD-3-clause) 39 | /lib 40 | /asf4 (Apache-2.0) 41 | /axtls (BSD-3-clause) 42 | /config 43 | /scripts 44 | /config (GPL-2.0-or-later) 45 | /Rules.mak (GPL-2.0) 46 | /berkeley-db-1xx (BSD-4-clause) 47 | /btstack (See btstack/LICENSE) 48 | /cmsis (BSD-3-clause) 49 | /crypto-algorithms (NONE) 50 | /libhydrogen (ISC) 51 | /littlefs (BSD-3-clause) 52 | /lwip (BSD-3-clause) 53 | /mynewt-nimble (Apache-2.0) 54 | /nrfx (BSD-3-clause) 55 | /nxp_driver (BSD-3-Clause) 56 | /oofatfs (BSD-1-clause) 57 | /pico-sdk (BSD-3-clause) 58 | /re15 (BSD-3-clause) 59 | /stm32lib (BSD-3-clause) 60 | /tinytest (BSD-3-clause) 61 | /tinyusb (MIT) 62 | /uzlib (Zlib) 63 | /wiznet5k (MIT) 64 | /logo (uses OFL-1.1) 65 | /ports 66 | /cc3200 67 | /hal (BSD-3-clause) 68 | /simplelink (BSD-3-clause) 69 | /FreeRTOS (GPL-2.0 with FreeRTOS exception) 70 | /esp32 71 | /ppp_set_auth.* (Apache-2.0) 72 | /rp2 73 | /mutex_extra.c (BSD-3-clause) 74 | /stm32 75 | /usbd*.c (MCD-ST Liberty SW License Agreement V2) 76 | /stm32_it.* (MIT + BSD-3-clause) 77 | /system_stm32*.c (MIT + BSD-3-clause) 78 | /boards 79 | /startup_stm32*.s (BSD-3-clause) 80 | /*/stm32*.h (BSD-3-clause) 81 | /usbdev (MCD-ST Liberty SW License Agreement V2) 82 | /usbhost (MCD-ST Liberty SW License Agreement V2) 83 | /zephyr 84 | /src (Apache-2.0) 85 | /tools 86 | /dfu.py (LGPL-3.0-only) 87 | -------------------------------------------------------------------------------- /firmware/firmware.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/firmware/firmware.bin -------------------------------------------------------------------------------- /fonts/bitmap/README.md: -------------------------------------------------------------------------------- 1 | # Included Font Files 2 | 3 | Frozen font files are included in the firmware. 4 | 5 | ## Bit mapped fonts for use with Text method 6 | 7 | The font_from_romfont utility can convert fonts from the font-bin directory of 8 | spacerace's https://github.com/spacerace/romfont repo. 9 | 10 | ### 128 Character Bit Mapped Fonts 11 | 12 | Frozen | Font | Example 13 | ------ | ------------------------------------------------------ | ----------------------------- 14 | Yes | [vga1_8x8.py](/fonts/bitmap/vga1_8x8.py) | ![Image](/docs/vga1_8x8.png) 15 | Yes | [vga1_16x16.py](/fonts/bitmap/vga1_16x16.py) | ![Image](/docs/vga1_16x16.png) 16 | Yes | [vga1_16x32.py](/fonts/bitmap/vga1_16x32.py) | ![Image](/docs/vga1_16x32.png) 17 | Yes | [vga1_bold_16x16.py](/fonts/bitmap/vga1_bold_16x16.py) | ![Image](/docs/vga1_bold_16x16.png) 18 | Yes | [vga1_bold_16x32.py](/fonts/bitmap/vga1_bold_16x32.py) | ![Image](/docs/vga1_bold_16x32.png) 19 | 20 | 21 | ### 256 Character Bit Mapped Fonts 22 | 23 | Frozen | Font | Example 24 | ------ | ------------------------------------------------------ | -------------------------- 25 | No | [vga2_8x8.py](/fonts/bitmap/vga2_8x8.py) | ![Image](/docs/vga2_8x8.png) 26 | No | [vga2_8x16.py](/fonts/bitmap/vga2_8x16.py) | ![Image](/docs/vga2_8x16.png) 27 | No | [vga2_16x16.py](/fonts/bitmap/vga2_16x16.py) | ![Image](/docs/vga2_16x16.png) 28 | No | [vga2_16x32.py](/fonts/bitmap/vga2_16x32.py) | ![Image](/docs/vga2_16x32.png) 29 | No | [vga2_bold_16x16.py](/fonts/bitmap/vga2_bold_16x16.py) | ![Image](/docs/vga2_bold_16x16.png) 30 | No | [vga2_bold_16x32.py](/fonts/bitmap/vga2_bold_16x32.py) | ![Image](/docs/vga2_bold_16x32.png) 31 | 32 | -------------------------------------------------------------------------------- /fonts/bitmap/vga1_8x16.py: -------------------------------------------------------------------------------- 1 | """converted from vga_8x16.bin """ 2 | WIDTH = 8 3 | HEIGHT = 16 4 | FIRST = 0x20 5 | LAST = 0x7f 6 | _FONT =\ 7 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 8 | b'\x00\x00\x18\x3c\x3c\x3c\x18\x18\x18\x00\x18\x18\x00\x00\x00\x00'\ 9 | b'\x00\x66\x66\x66\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 10 | b'\x00\x00\x00\x6c\x6c\xfe\x6c\x6c\x6c\xfe\x6c\x6c\x00\x00\x00\x00'\ 11 | b'\x18\x18\x7c\xc6\xc2\xc0\x7c\x06\x06\x86\xc6\x7c\x18\x18\x00\x00'\ 12 | b'\x00\x00\x00\x00\xc2\xc6\x0c\x18\x30\x60\xc6\x86\x00\x00\x00\x00'\ 13 | b'\x00\x00\x38\x6c\x6c\x38\x76\xdc\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 14 | b'\x00\x30\x30\x30\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 15 | b'\x00\x00\x0c\x18\x30\x30\x30\x30\x30\x30\x18\x0c\x00\x00\x00\x00'\ 16 | b'\x00\x00\x30\x18\x0c\x0c\x0c\x0c\x0c\x0c\x18\x30\x00\x00\x00\x00'\ 17 | b'\x00\x00\x00\x00\x00\x66\x3c\xff\x3c\x66\x00\x00\x00\x00\x00\x00'\ 18 | b'\x00\x00\x00\x00\x00\x18\x18\x7e\x18\x18\x00\x00\x00\x00\x00\x00'\ 19 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x18\x18\x30\x00\x00\x00'\ 20 | b'\x00\x00\x00\x00\x00\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00'\ 21 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x18\x00\x00\x00\x00'\ 22 | b'\x00\x00\x00\x00\x02\x06\x0c\x18\x30\x60\xc0\x80\x00\x00\x00\x00'\ 23 | b'\x00\x00\x38\x6c\xc6\xc6\xd6\xd6\xc6\xc6\x6c\x38\x00\x00\x00\x00'\ 24 | b'\x00\x00\x18\x38\x78\x18\x18\x18\x18\x18\x18\x7e\x00\x00\x00\x00'\ 25 | b'\x00\x00\x7c\xc6\x06\x0c\x18\x30\x60\xc0\xc6\xfe\x00\x00\x00\x00'\ 26 | b'\x00\x00\x7c\xc6\x06\x06\x3c\x06\x06\x06\xc6\x7c\x00\x00\x00\x00'\ 27 | b'\x00\x00\x0c\x1c\x3c\x6c\xcc\xfe\x0c\x0c\x0c\x1e\x00\x00\x00\x00'\ 28 | b'\x00\x00\xfe\xc0\xc0\xc0\xfc\x06\x06\x06\xc6\x7c\x00\x00\x00\x00'\ 29 | b'\x00\x00\x38\x60\xc0\xc0\xfc\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 30 | b'\x00\x00\xfe\xc6\x06\x06\x0c\x18\x30\x30\x30\x30\x00\x00\x00\x00'\ 31 | b'\x00\x00\x7c\xc6\xc6\xc6\x7c\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 32 | b'\x00\x00\x7c\xc6\xc6\xc6\x7e\x06\x06\x06\x0c\x78\x00\x00\x00\x00'\ 33 | b'\x00\x00\x00\x00\x18\x18\x00\x00\x00\x18\x18\x00\x00\x00\x00\x00'\ 34 | b'\x00\x00\x00\x00\x18\x18\x00\x00\x00\x18\x18\x30\x00\x00\x00\x00'\ 35 | b'\x00\x00\x00\x06\x0c\x18\x30\x60\x30\x18\x0c\x06\x00\x00\x00\x00'\ 36 | b'\x00\x00\x00\x00\x00\x7e\x00\x00\x7e\x00\x00\x00\x00\x00\x00\x00'\ 37 | b'\x00\x00\x00\x60\x30\x18\x0c\x06\x0c\x18\x30\x60\x00\x00\x00\x00'\ 38 | b'\x00\x00\x7c\xc6\xc6\x0c\x18\x18\x18\x00\x18\x18\x00\x00\x00\x00'\ 39 | b'\x00\x00\x00\x7c\xc6\xc6\xde\xde\xde\xdc\xc0\x7c\x00\x00\x00\x00'\ 40 | b'\x00\x00\x10\x38\x6c\xc6\xc6\xfe\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 41 | b'\x00\x00\xfc\x66\x66\x66\x7c\x66\x66\x66\x66\xfc\x00\x00\x00\x00'\ 42 | b'\x00\x00\x3c\x66\xc2\xc0\xc0\xc0\xc0\xc2\x66\x3c\x00\x00\x00\x00'\ 43 | b'\x00\x00\xf8\x6c\x66\x66\x66\x66\x66\x66\x6c\xf8\x00\x00\x00\x00'\ 44 | b'\x00\x00\xfe\x66\x62\x68\x78\x68\x60\x62\x66\xfe\x00\x00\x00\x00'\ 45 | b'\x00\x00\xfe\x66\x62\x68\x78\x68\x60\x60\x60\xf0\x00\x00\x00\x00'\ 46 | b'\x00\x00\x3c\x66\xc2\xc0\xc0\xde\xc6\xc6\x66\x3a\x00\x00\x00\x00'\ 47 | b'\x00\x00\xc6\xc6\xc6\xc6\xfe\xc6\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 48 | b'\x00\x00\x3c\x18\x18\x18\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 49 | b'\x00\x00\x1e\x0c\x0c\x0c\x0c\x0c\xcc\xcc\xcc\x78\x00\x00\x00\x00'\ 50 | b'\x00\x00\xe6\x66\x66\x6c\x78\x78\x6c\x66\x66\xe6\x00\x00\x00\x00'\ 51 | b'\x00\x00\xf0\x60\x60\x60\x60\x60\x60\x62\x66\xfe\x00\x00\x00\x00'\ 52 | b'\x00\x00\xc6\xee\xfe\xfe\xd6\xc6\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 53 | b'\x00\x00\xc6\xe6\xf6\xfe\xde\xce\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 54 | b'\x00\x00\x7c\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 55 | b'\x00\x00\xfc\x66\x66\x66\x7c\x60\x60\x60\x60\xf0\x00\x00\x00\x00'\ 56 | b'\x00\x00\x7c\xc6\xc6\xc6\xc6\xc6\xc6\xd6\xde\x7c\x0c\x0e\x00\x00'\ 57 | b'\x00\x00\xfc\x66\x66\x66\x7c\x6c\x66\x66\x66\xe6\x00\x00\x00\x00'\ 58 | b'\x00\x00\x7c\xc6\xc6\x60\x38\x0c\x06\xc6\xc6\x7c\x00\x00\x00\x00'\ 59 | b'\x00\x00\x7e\x7e\x5a\x18\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 60 | b'\x00\x00\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 61 | b'\x00\x00\xc6\xc6\xc6\xc6\xc6\xc6\xc6\x6c\x38\x10\x00\x00\x00\x00'\ 62 | b'\x00\x00\xc6\xc6\xc6\xc6\xd6\xd6\xd6\xfe\xee\x6c\x00\x00\x00\x00'\ 63 | b'\x00\x00\xc6\xc6\x6c\x7c\x38\x38\x7c\x6c\xc6\xc6\x00\x00\x00\x00'\ 64 | b'\x00\x00\x66\x66\x66\x66\x3c\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 65 | b'\x00\x00\xfe\xc6\x86\x0c\x18\x30\x60\xc2\xc6\xfe\x00\x00\x00\x00'\ 66 | b'\x00\x00\x3c\x30\x30\x30\x30\x30\x30\x30\x30\x3c\x00\x00\x00\x00'\ 67 | b'\x00\x00\x00\x80\xc0\xe0\x70\x38\x1c\x0e\x06\x02\x00\x00\x00\x00'\ 68 | b'\x00\x00\x3c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x3c\x00\x00\x00\x00'\ 69 | b'\x10\x38\x6c\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 70 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00'\ 71 | b'\x00\x30\x18\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 72 | b'\x00\x00\x00\x00\x00\x78\x0c\x7c\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 73 | b'\x00\x00\xe0\x60\x60\x78\x6c\x66\x66\x66\x66\x7c\x00\x00\x00\x00'\ 74 | b'\x00\x00\x00\x00\x00\x7c\xc6\xc0\xc0\xc0\xc6\x7c\x00\x00\x00\x00'\ 75 | b'\x00\x00\x1c\x0c\x0c\x3c\x6c\xcc\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 76 | b'\x00\x00\x00\x00\x00\x7c\xc6\xfe\xc0\xc0\xc6\x7c\x00\x00\x00\x00'\ 77 | b'\x00\x00\x1c\x36\x32\x30\x78\x30\x30\x30\x30\x78\x00\x00\x00\x00'\ 78 | b'\x00\x00\x00\x00\x00\x76\xcc\xcc\xcc\xcc\xcc\x7c\x0c\xcc\x78\x00'\ 79 | b'\x00\x00\xe0\x60\x60\x6c\x76\x66\x66\x66\x66\xe6\x00\x00\x00\x00'\ 80 | b'\x00\x00\x18\x18\x00\x38\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 81 | b'\x00\x00\x06\x06\x00\x0e\x06\x06\x06\x06\x06\x06\x66\x66\x3c\x00'\ 82 | b'\x00\x00\xe0\x60\x60\x66\x6c\x78\x78\x6c\x66\xe6\x00\x00\x00\x00'\ 83 | b'\x00\x00\x38\x18\x18\x18\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 84 | b'\x00\x00\x00\x00\x00\xec\xfe\xd6\xd6\xd6\xd6\xc6\x00\x00\x00\x00'\ 85 | b'\x00\x00\x00\x00\x00\xdc\x66\x66\x66\x66\x66\x66\x00\x00\x00\x00'\ 86 | b'\x00\x00\x00\x00\x00\x7c\xc6\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 87 | b'\x00\x00\x00\x00\x00\xdc\x66\x66\x66\x66\x66\x7c\x60\x60\xf0\x00'\ 88 | b'\x00\x00\x00\x00\x00\x76\xcc\xcc\xcc\xcc\xcc\x7c\x0c\x0c\x1e\x00'\ 89 | b'\x00\x00\x00\x00\x00\xdc\x76\x66\x60\x60\x60\xf0\x00\x00\x00\x00'\ 90 | b'\x00\x00\x00\x00\x00\x7c\xc6\x60\x38\x0c\xc6\x7c\x00\x00\x00\x00'\ 91 | b'\x00\x00\x10\x30\x30\xfc\x30\x30\x30\x30\x36\x1c\x00\x00\x00\x00'\ 92 | b'\x00\x00\x00\x00\x00\xcc\xcc\xcc\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 93 | b'\x00\x00\x00\x00\x00\xc6\xc6\xc6\xc6\xc6\x6c\x38\x00\x00\x00\x00'\ 94 | b'\x00\x00\x00\x00\x00\xc6\xc6\xd6\xd6\xd6\xfe\x6c\x00\x00\x00\x00'\ 95 | b'\x00\x00\x00\x00\x00\xc6\x6c\x38\x38\x38\x6c\xc6\x00\x00\x00\x00'\ 96 | b'\x00\x00\x00\x00\x00\xc6\xc6\xc6\xc6\xc6\xc6\x7e\x06\x0c\xf8\x00'\ 97 | b'\x00\x00\x00\x00\x00\xfe\xcc\x18\x30\x60\xc6\xfe\x00\x00\x00\x00'\ 98 | b'\x00\x00\x0e\x18\x18\x18\x70\x18\x18\x18\x18\x0e\x00\x00\x00\x00'\ 99 | b'\x00\x00\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x00\x00\x00\x00'\ 100 | b'\x00\x00\x70\x18\x18\x18\x0e\x18\x18\x18\x18\x70\x00\x00\x00\x00'\ 101 | b'\x00\x76\xdc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 102 | b'\x00\x00\x00\x00\x10\x38\x6c\xc6\xc6\xc6\xfe\x00\x00\x00\x00\x00'\ 103 | 104 | FONT = memoryview(_FONT) 105 | -------------------------------------------------------------------------------- /fonts/bitmap/vga1_8x8.py: -------------------------------------------------------------------------------- 1 | """converted from vga_8x8.bin """ 2 | WIDTH = 8 3 | HEIGHT = 8 4 | FIRST = 0x20 5 | LAST = 0x7f 6 | _FONT =\ 7 | b'\x00\x00\x00\x00\x00\x00\x00\x00'\ 8 | b'\x18\x3c\x3c\x18\x18\x00\x18\x00'\ 9 | b'\x66\x66\x24\x00\x00\x00\x00\x00'\ 10 | b'\x6c\x6c\xfe\x6c\xfe\x6c\x6c\x00'\ 11 | b'\x18\x3e\x60\x3c\x06\x7c\x18\x00'\ 12 | b'\x00\xc6\xcc\x18\x30\x66\xc6\x00'\ 13 | b'\x38\x6c\x38\x76\xdc\xcc\x76\x00'\ 14 | b'\x18\x18\x30\x00\x00\x00\x00\x00'\ 15 | b'\x0c\x18\x30\x30\x30\x18\x0c\x00'\ 16 | b'\x30\x18\x0c\x0c\x0c\x18\x30\x00'\ 17 | b'\x00\x66\x3c\xff\x3c\x66\x00\x00'\ 18 | b'\x00\x18\x18\x7e\x18\x18\x00\x00'\ 19 | b'\x00\x00\x00\x00\x00\x18\x18\x30'\ 20 | b'\x00\x00\x00\x7e\x00\x00\x00\x00'\ 21 | b'\x00\x00\x00\x00\x00\x18\x18\x00'\ 22 | b'\x06\x0c\x18\x30\x60\xc0\x80\x00'\ 23 | b'\x38\x6c\xc6\xd6\xc6\x6c\x38\x00'\ 24 | b'\x18\x38\x18\x18\x18\x18\x7e\x00'\ 25 | b'\x7c\xc6\x06\x1c\x30\x66\xfe\x00'\ 26 | b'\x7c\xc6\x06\x3c\x06\xc6\x7c\x00'\ 27 | b'\x1c\x3c\x6c\xcc\xfe\x0c\x1e\x00'\ 28 | b'\xfe\xc0\xc0\xfc\x06\xc6\x7c\x00'\ 29 | b'\x38\x60\xc0\xfc\xc6\xc6\x7c\x00'\ 30 | b'\xfe\xc6\x0c\x18\x30\x30\x30\x00'\ 31 | b'\x7c\xc6\xc6\x7c\xc6\xc6\x7c\x00'\ 32 | b'\x7c\xc6\xc6\x7e\x06\x0c\x78\x00'\ 33 | b'\x00\x18\x18\x00\x00\x18\x18\x00'\ 34 | b'\x00\x18\x18\x00\x00\x18\x18\x30'\ 35 | b'\x06\x0c\x18\x30\x18\x0c\x06\x00'\ 36 | b'\x00\x00\x7e\x00\x00\x7e\x00\x00'\ 37 | b'\x60\x30\x18\x0c\x18\x30\x60\x00'\ 38 | b'\x7c\xc6\x0c\x18\x18\x00\x18\x00'\ 39 | b'\x7c\xc6\xde\xde\xde\xc0\x78\x00'\ 40 | b'\x38\x6c\xc6\xfe\xc6\xc6\xc6\x00'\ 41 | b'\xfc\x66\x66\x7c\x66\x66\xfc\x00'\ 42 | b'\x3c\x66\xc0\xc0\xc0\x66\x3c\x00'\ 43 | b'\xf8\x6c\x66\x66\x66\x6c\xf8\x00'\ 44 | b'\xfe\x62\x68\x78\x68\x62\xfe\x00'\ 45 | b'\xfe\x62\x68\x78\x68\x60\xf0\x00'\ 46 | b'\x3c\x66\xc0\xc0\xce\x66\x3a\x00'\ 47 | b'\xc6\xc6\xc6\xfe\xc6\xc6\xc6\x00'\ 48 | b'\x3c\x18\x18\x18\x18\x18\x3c\x00'\ 49 | b'\x1e\x0c\x0c\x0c\xcc\xcc\x78\x00'\ 50 | b'\xe6\x66\x6c\x78\x6c\x66\xe6\x00'\ 51 | b'\xf0\x60\x60\x60\x62\x66\xfe\x00'\ 52 | b'\xc6\xee\xfe\xfe\xd6\xc6\xc6\x00'\ 53 | b'\xc6\xe6\xf6\xde\xce\xc6\xc6\x00'\ 54 | b'\x7c\xc6\xc6\xc6\xc6\xc6\x7c\x00'\ 55 | b'\xfc\x66\x66\x7c\x60\x60\xf0\x00'\ 56 | b'\x7c\xc6\xc6\xc6\xc6\xce\x7c\x0e'\ 57 | b'\xfc\x66\x66\x7c\x6c\x66\xe6\x00'\ 58 | b'\x3c\x66\x30\x18\x0c\x66\x3c\x00'\ 59 | b'\x7e\x7e\x5a\x18\x18\x18\x3c\x00'\ 60 | b'\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00'\ 61 | b'\xc6\xc6\xc6\xc6\xc6\x6c\x38\x00'\ 62 | b'\xc6\xc6\xc6\xd6\xd6\xfe\x6c\x00'\ 63 | b'\xc6\xc6\x6c\x38\x6c\xc6\xc6\x00'\ 64 | b'\x66\x66\x66\x3c\x18\x18\x3c\x00'\ 65 | b'\xfe\xc6\x8c\x18\x32\x66\xfe\x00'\ 66 | b'\x3c\x30\x30\x30\x30\x30\x3c\x00'\ 67 | b'\xc0\x60\x30\x18\x0c\x06\x02\x00'\ 68 | b'\x3c\x0c\x0c\x0c\x0c\x0c\x3c\x00'\ 69 | b'\x10\x38\x6c\xc6\x00\x00\x00\x00'\ 70 | b'\x00\x00\x00\x00\x00\x00\x00\xff'\ 71 | b'\x30\x18\x0c\x00\x00\x00\x00\x00'\ 72 | b'\x00\x00\x78\x0c\x7c\xcc\x76\x00'\ 73 | b'\xe0\x60\x7c\x66\x66\x66\xdc\x00'\ 74 | b'\x00\x00\x7c\xc6\xc0\xc6\x7c\x00'\ 75 | b'\x1c\x0c\x7c\xcc\xcc\xcc\x76\x00'\ 76 | b'\x00\x00\x7c\xc6\xfe\xc0\x7c\x00'\ 77 | b'\x3c\x66\x60\xf8\x60\x60\xf0\x00'\ 78 | b'\x00\x00\x76\xcc\xcc\x7c\x0c\xf8'\ 79 | b'\xe0\x60\x6c\x76\x66\x66\xe6\x00'\ 80 | b'\x18\x00\x38\x18\x18\x18\x3c\x00'\ 81 | b'\x06\x00\x06\x06\x06\x66\x66\x3c'\ 82 | b'\xe0\x60\x66\x6c\x78\x6c\xe6\x00'\ 83 | b'\x38\x18\x18\x18\x18\x18\x3c\x00'\ 84 | b'\x00\x00\xec\xfe\xd6\xd6\xd6\x00'\ 85 | b'\x00\x00\xdc\x66\x66\x66\x66\x00'\ 86 | b'\x00\x00\x7c\xc6\xc6\xc6\x7c\x00'\ 87 | b'\x00\x00\xdc\x66\x66\x7c\x60\xf0'\ 88 | b'\x00\x00\x76\xcc\xcc\x7c\x0c\x1e'\ 89 | b'\x00\x00\xdc\x76\x60\x60\xf0\x00'\ 90 | b'\x00\x00\x7e\xc0\x7c\x06\xfc\x00'\ 91 | b'\x30\x30\xfc\x30\x30\x36\x1c\x00'\ 92 | b'\x00\x00\xcc\xcc\xcc\xcc\x76\x00'\ 93 | b'\x00\x00\xc6\xc6\xc6\x6c\x38\x00'\ 94 | b'\x00\x00\xc6\xd6\xd6\xfe\x6c\x00'\ 95 | b'\x00\x00\xc6\x6c\x38\x6c\xc6\x00'\ 96 | b'\x00\x00\xc6\xc6\xc6\x7e\x06\xfc'\ 97 | b'\x00\x00\x7e\x4c\x18\x32\x7e\x00'\ 98 | b'\x0e\x18\x18\x70\x18\x18\x0e\x00'\ 99 | b'\x18\x18\x18\x18\x18\x18\x18\x00'\ 100 | b'\x70\x18\x18\x0e\x18\x18\x70\x00'\ 101 | b'\x76\xdc\x00\x00\x00\x00\x00\x00'\ 102 | b'\x00\x10\x38\x6c\xc6\xc6\xfe\x00'\ 103 | 104 | FONT = memoryview(_FONT) 105 | -------------------------------------------------------------------------------- /fonts/bitmap/vga_8x16.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/bitmap/vga_8x16.bin -------------------------------------------------------------------------------- /fonts/bitmap/vga_8x8.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/bitmap/vga_8x8.bin -------------------------------------------------------------------------------- /fonts/truetype/Chango-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/truetype/Chango-Regular.ttf -------------------------------------------------------------------------------- /fonts/truetype/LICENSE_OFL.txt: -------------------------------------------------------------------------------- 1 | This Font Software is licensed under the SIL Open Font License, 2 | Version 1.1. 3 | 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | ----------------------------------------------------------- 8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 9 | ----------------------------------------------------------- 10 | 11 | PREAMBLE 12 | The goals of the Open Font License (OFL) are to stimulate worldwide 13 | development of collaborative font projects, to support the font 14 | creation efforts of academic and linguistic communities, and to 15 | provide a free and open framework in which fonts may be shared and 16 | improved in partnership with others. 17 | 18 | The OFL allows the licensed fonts to be used, studied, modified and 19 | redistributed freely as long as they are not sold by themselves. The 20 | fonts, including any derivative works, can be bundled, embedded, 21 | redistributed and/or sold with any software provided that any reserved 22 | names are not used by derivative works. The fonts and derivatives, 23 | however, cannot be released under any other type of license. The 24 | requirement for fonts to remain under this license does not apply to 25 | any document created using the fonts or their derivatives. 26 | 27 | DEFINITIONS 28 | "Font Software" refers to the set of files released by the Copyright 29 | Holder(s) under this license and clearly marked as such. This may 30 | include source files, build scripts and documentation. 31 | 32 | "Reserved Font Name" refers to any names specified as such after the 33 | copyright statement(s). 34 | 35 | "Original Version" refers to the collection of Font Software 36 | components as distributed by the Copyright Holder(s). 37 | 38 | "Modified Version" refers to any derivative made by adding to, 39 | deleting, or substituting -- in part or in whole -- any of the 40 | components of the Original Version, by changing formats or by porting 41 | the Font Software to a new environment. 42 | 43 | "Author" refers to any designer, engineer, programmer, technical 44 | writer or other person who contributed to the Font Software. 45 | 46 | PERMISSION & CONDITIONS 47 | Permission is hereby granted, free of charge, to any person obtaining 48 | a copy of the Font Software, to use, study, copy, merge, embed, 49 | modify, redistribute, and sell modified and unmodified copies of the 50 | Font Software, subject to the following conditions: 51 | 52 | 1) Neither the Font Software nor any of its individual components, in 53 | Original or Modified Versions, may be sold by itself. 54 | 55 | 2) Original or Modified Versions of the Font Software may be bundled, 56 | redistributed and/or sold with any software, provided that each copy 57 | contains the above copyright notice and this license. These can be 58 | included either as stand-alone text files, human-readable headers or 59 | in the appropriate machine-readable metadata fields within text or 60 | binary files as long as those fields can be easily viewed by the user. 61 | 62 | 3) No Modified Version of the Font Software may use the Reserved Font 63 | Name(s) unless explicit written permission is granted by the 64 | corresponding Copyright Holder. This restriction only applies to the 65 | primary font name as presented to the users. 66 | 67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 68 | Software shall not be used to promote, endorse or advertise any 69 | Modified Version, except to acknowledge the contribution(s) of the 70 | Copyright Holder(s) and the Author(s) or with their explicit written 71 | permission. 72 | 73 | 5) The Font Software, modified or unmodified, in part or in whole, 74 | must be distributed entirely under this license, and must not be 75 | distributed under any other license. The requirement for fonts to 76 | remain under this license does not apply to any document created using 77 | the Font Software. 78 | 79 | TERMINATION 80 | This license becomes null and void if any of the above conditions are 81 | not met. 82 | 83 | DISCLAIMER 84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 92 | OTHER DEALINGS IN THE FONT SOFTWARE. 93 | -------------------------------------------------------------------------------- /fonts/truetype/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/truetype/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /fonts/truetype/NotoSansMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/truetype/NotoSansMono-Regular.ttf -------------------------------------------------------------------------------- /fonts/truetype/NotoSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/truetype/NotoSerif-Regular.ttf -------------------------------------------------------------------------------- /fonts/truetype/README.md: -------------------------------------------------------------------------------- 1 | # SIL Open Font License fonts 2 | 3 | Here are a few of the SIL Open Font Licensed fonts I used for testing the 4 | `monofont2bitmap` and `font2bitmap` utilies. 5 | 6 | ## Proportional fonts 7 | 8 | These are suitable for use with `font2bitmap` utility and the drivers `write` 9 | method. 10 | 11 | - Chango-Regular.ttf 12 | - NotoSans-Regular.ttf 13 | - NotoSerif-Regular.ttf 14 | 15 | ## Monospaced fonts 16 | 17 | This font is suitable for use with `font2bitmap` utility and the drivers `write` 18 | method. It can also be used with the `monofont2bitmap` utility and the drivers 19 | `bitmap` method. 20 | 21 | - inconsolata-700.ttf 22 | - NotoSansMono-Regular.ttf 23 | 24 | -------------------------------------------------------------------------------- /fonts/truetype/inconsolata-700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/russhughes/st7789s3_mpy/2dd564d019c81f4c2531e07225e4b89b01ccf6b7/fonts/truetype/inconsolata-700.ttf -------------------------------------------------------------------------------- /fonts/vector/README.md: -------------------------------------------------------------------------------- 1 | # Included Font Files 2 | 3 | Frozen font files are included in the firmware. 4 | 5 | ## Vector fonts for use with the Draw method 6 | 7 | ### Hershey Vector Fonts 8 | 9 | Frozen | Font | Example 10 | ------ | ---------------------------------------- | ---------------------- 11 | No | [astrol.py](/fonts/vector/astrol.py) | ![Image](/docs/astrol.svg) 12 | Yes | [cyrilc.py](/fonts/vector/cyrilc.py) | ![Image](/docs/cyrilc.svg) 13 | Yes | [gotheng.py](/fonts/vector/gotheng.py) | ![Image](/docs/gotheng.svg) 14 | Yes | [gothger.py](/fonts/vector/gothger.py) | ![Image](/docs/gothger.svg) 15 | Yes | [gothita.py](/fonts/vector/gothita.py) | ![Image](/docs/gothita.svg) 16 | Yes | [greekc.py](/fonts/vector/greekc.py) | ![Image](/docs/greekc.svg) 17 | Yes | [greekcs.py](/fonts/vector/greekcs.py) | ![Image](/docs/greekcs.svg) 18 | Yes | [greekp.py](/fonts/vector/greekp.py) | ![Image](/docs/greekp.svg) 19 | Yes | [greeks.py](/fonts/vector/greeks.py) | ![Image](/docs/greeks.svg) 20 | Yes | [italicc.py](/fonts/vector/italicc.py) | ![Image](/docs/italicc.svg) 21 | Yes | [italiccs.py](/fonts/vector/italiccs.py) | ![Image](/docs/italiccs.svg) 22 | Yes | [italict.py](/fonts/vector/italict.py) | ![Image](/docs/italict.svg) 23 | Yes | [lowmat.py](/fonts/vector/lowmat.py) | ![Image](/docs/lowmat.svg) 24 | Yes | [marker.py](/fonts/vector/marker.py) | ![Image](/docs/marker.svg) 25 | Yes | [meteo.py](/fonts/vector/meteo.py) | ![Image](/docs/meteo.svg) 26 | Yes | [music.py](/fonts/vector/music.py) | ![Image](/docs/music.svg) 27 | Yes | [romanc.py](/fonts/vector/romanc.py) | ![Image](/docs/romanc.svg) 28 | Yes | [romancs.py](/fonts/vector/romancs.py) | ![Image](/docs/romancs.svg) 29 | Yes | [romand.py](/fonts/vector/romand.py) | ![Image](/docs/romand.svg) 30 | Yes | [romanp.py](/fonts/vector/romanp.py) | ![Image](/docs/romanp.svg) 31 | Yes | [romans.py](/fonts/vector/romans.py) | ![Image](/docs/romans.svg) 32 | Yes | [romant.py](/fonts/vector/romant.py) | ![Image](/docs/romant.svg) 33 | Yes | [scriptc.py](/fonts/vector/scriptc.py) | ![Image](/docs/scriptc.svg) 34 | Yes | [scripts.py](/fonts/vector/scripts.py) | ![Image](/docs/scripts.svg) 35 | Yes | [symbol.py](/fonts/vector/symbol.py) | ![Image](/docs/symbol.svg) 36 | Yes | [uppmat.py](/fonts/vector/uppmat.py) | ![Image](/docs/uppmat.svg) 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /fonts/vector/marker.py: -------------------------------------------------------------------------------- 1 | WIDTH = 26 2 | HEIGHT = 26 3 | FIRST = 0x20 4 | LAST = 0x7f 5 | 6 | _font =\ 7 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 8 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 9 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 10 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 11 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 12 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 13 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x11\x4b\x59\x51\x4b\x4e'\ 14 | b'\x4c\x4c\x4e\x4b\x51\x4b\x53\x4c\x56\x4e\x58\x51\x59\x53\x59'\ 15 | b'\x56\x58\x58\x56\x59\x53\x59\x51\x58\x4e\x56\x4c\x53\x4b\x51'\ 16 | b'\x4b\x05\x4c\x58\x4c\x4c\x4c\x58\x58\x58\x58\x4c\x4c\x4c\x04'\ 17 | b'\x4b\x59\x52\x4a\x4b\x56\x59\x56\x52\x4a\x05\x4c\x58\x52\x48'\ 18 | b'\x4c\x52\x52\x5c\x58\x52\x52\x48\x0b\x4a\x5a\x52\x49\x50\x4f'\ 19 | b'\x4a\x4f\x4f\x53\x4d\x59\x52\x55\x57\x59\x55\x53\x5a\x4f\x54'\ 20 | b'\x4f\x52\x49\x0d\x4c\x58\x50\x4c\x50\x50\x4c\x50\x4c\x54\x50'\ 21 | b'\x54\x50\x58\x54\x58\x54\x54\x58\x54\x58\x50\x54\x50\x54\x4c'\ 22 | b'\x50\x4c\x05\x4b\x59\x52\x4b\x52\x59\x20\x52\x4b\x52\x59\x52'\ 23 | b'\x05\x4d\x57\x4d\x4d\x57\x57\x20\x52\x57\x4d\x4d\x57\x08\x4d'\ 24 | b'\x57\x52\x4c\x52\x58\x20\x52\x4d\x4f\x57\x55\x20\x52\x57\x4f'\ 25 | b'\x4d\x55\x22\x4e\x56\x51\x4e\x4f\x4f\x4e\x51\x4e\x53\x4f\x55'\ 26 | b'\x51\x56\x53\x56\x55\x55\x56\x53\x56\x51\x55\x4f\x53\x4e\x51'\ 27 | b'\x4e\x20\x52\x4f\x51\x4f\x53\x20\x52\x50\x50\x50\x54\x20\x52'\ 28 | b'\x51\x4f\x51\x55\x20\x52\x52\x4f\x52\x55\x20\x52\x53\x4f\x53'\ 29 | b'\x55\x20\x52\x54\x50\x54\x54\x20\x52\x55\x51\x55\x53\x1a\x4e'\ 30 | b'\x56\x4e\x4e\x4e\x56\x56\x56\x56\x4e\x4e\x4e\x20\x52\x4f\x4f'\ 31 | b'\x4f\x55\x20\x52\x50\x4f\x50\x55\x20\x52\x51\x4f\x51\x55\x20'\ 32 | b'\x52\x52\x4f\x52\x55\x20\x52\x53\x4f\x53\x55\x20\x52\x54\x4f'\ 33 | b'\x54\x55\x20\x52\x55\x4f\x55\x55\x10\x4d\x57\x52\x4c\x4d\x55'\ 34 | b'\x57\x55\x52\x4c\x20\x52\x52\x4f\x4f\x54\x20\x52\x52\x4f\x55'\ 35 | b'\x54\x20\x52\x52\x52\x51\x54\x20\x52\x52\x52\x53\x54\x10\x4c'\ 36 | b'\x55\x4c\x52\x55\x57\x55\x4d\x4c\x52\x20\x52\x4f\x52\x54\x55'\ 37 | b'\x20\x52\x4f\x52\x54\x4f\x20\x52\x52\x52\x54\x53\x20\x52\x52'\ 38 | b'\x52\x54\x51\x10\x4d\x57\x52\x58\x57\x4f\x4d\x4f\x52\x58\x20'\ 39 | b'\x52\x52\x55\x55\x50\x20\x52\x52\x55\x4f\x50\x20\x52\x52\x52'\ 40 | b'\x53\x50\x20\x52\x52\x52\x51\x50\x10\x4f\x58\x58\x52\x4f\x4d'\ 41 | b'\x4f\x57\x58\x52\x20\x52\x55\x52\x50\x4f\x20\x52\x55\x52\x50'\ 42 | b'\x55\x20\x52\x52\x52\x50\x51\x20\x52\x52\x52\x50\x53\x08\x44'\ 43 | b'\x60\x44\x52\x60\x52\x20\x52\x44\x52\x52\x62\x20\x52\x60\x52'\ 44 | b'\x52\x62\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00'\ 45 | b'\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00'\ 46 | b'\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00'\ 47 | b'\x4a\x5a\x00\x4a\x5a\x11\x4b\x59\x51\x4b\x4e\x4c\x4c\x4e\x4b'\ 48 | b'\x51\x4b\x53\x4c\x56\x4e\x58\x51\x59\x53\x59\x56\x58\x58\x56'\ 49 | b'\x59\x53\x59\x51\x58\x4e\x56\x4c\x53\x4b\x51\x4b\x05\x4c\x58'\ 50 | b'\x4c\x4c\x4c\x58\x58\x58\x58\x4c\x4c\x4c\x04\x4b\x59\x52\x4a'\ 51 | b'\x4b\x56\x59\x56\x52\x4a\x05\x4c\x58\x52\x48\x4c\x52\x52\x5c'\ 52 | b'\x58\x52\x52\x48\x0b\x4a\x5a\x52\x49\x50\x4f\x4a\x4f\x4f\x53'\ 53 | b'\x4d\x59\x52\x55\x57\x59\x55\x53\x5a\x4f\x54\x4f\x52\x49\x0d'\ 54 | b'\x4c\x58\x50\x4c\x50\x50\x4c\x50\x4c\x54\x50\x54\x50\x58\x54'\ 55 | b'\x58\x54\x54\x58\x54\x58\x50\x54\x50\x54\x4c\x50\x4c\x05\x4b'\ 56 | b'\x59\x52\x4b\x52\x59\x20\x52\x4b\x52\x59\x52\x05\x4d\x57\x4d'\ 57 | b'\x4d\x57\x57\x20\x52\x57\x4d\x4d\x57\x08\x4d\x57\x52\x4c\x52'\ 58 | b'\x58\x20\x52\x4d\x4f\x57\x55\x20\x52\x57\x4f\x4d\x55\x22\x4e'\ 59 | b'\x56\x51\x4e\x4f\x4f\x4e\x51\x4e\x53\x4f\x55\x51\x56\x53\x56'\ 60 | b'\x55\x55\x56\x53\x56\x51\x55\x4f\x53\x4e\x51\x4e\x20\x52\x4f'\ 61 | b'\x51\x4f\x53\x20\x52\x50\x50\x50\x54\x20\x52\x51\x4f\x51\x55'\ 62 | b'\x20\x52\x52\x4f\x52\x55\x20\x52\x53\x4f\x53\x55\x20\x52\x54'\ 63 | b'\x50\x54\x54\x20\x52\x55\x51\x55\x53\x1a\x4e\x56\x4e\x4e\x4e'\ 64 | b'\x56\x56\x56\x56\x4e\x4e\x4e\x20\x52\x4f\x4f\x4f\x55\x20\x52'\ 65 | b'\x50\x4f\x50\x55\x20\x52\x51\x4f\x51\x55\x20\x52\x52\x4f\x52'\ 66 | b'\x55\x20\x52\x53\x4f\x53\x55\x20\x52\x54\x4f\x54\x55\x20\x52'\ 67 | b'\x55\x4f\x55\x55\x10\x4d\x57\x52\x4c\x4d\x55\x57\x55\x52\x4c'\ 68 | b'\x20\x52\x52\x4f\x4f\x54\x20\x52\x52\x4f\x55\x54\x20\x52\x52'\ 69 | b'\x52\x51\x54\x20\x52\x52\x52\x53\x54\x10\x4c\x55\x4c\x52\x55'\ 70 | b'\x57\x55\x4d\x4c\x52\x20\x52\x4f\x52\x54\x55\x20\x52\x4f\x52'\ 71 | b'\x54\x4f\x20\x52\x52\x52\x54\x53\x20\x52\x52\x52\x54\x51\x10'\ 72 | b'\x4d\x57\x52\x58\x57\x4f\x4d\x4f\x52\x58\x20\x52\x52\x55\x55'\ 73 | b'\x50\x20\x52\x52\x55\x4f\x50\x20\x52\x52\x52\x53\x50\x20\x52'\ 74 | b'\x52\x52\x51\x50\x10\x4f\x58\x58\x52\x4f\x4d\x4f\x57\x58\x52'\ 75 | b'\x20\x52\x55\x52\x50\x4f\x20\x52\x55\x52\x50\x55\x20\x52\x52'\ 76 | b'\x52\x50\x51\x20\x52\x52\x52\x50\x53\x08\x44\x60\x44\x52\x60'\ 77 | b'\x52\x20\x52\x44\x52\x52\x62\x20\x52\x60\x52\x52\x62\x00\x4a'\ 78 | b'\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a'\ 79 | b'\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a'\ 80 | b'\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a'\ 81 | b'\x5a' 82 | 83 | _index =\ 84 | b'\x00\x00\x03\x00\x06\x00\x09\x00\x0c\x00\x0f\x00\x12\x00\x15'\ 85 | b'\x00\x18\x00\x1b\x00\x1e\x00\x21\x00\x24\x00\x27\x00\x2a\x00'\ 86 | b'\x2d\x00\x30\x00\x33\x00\x36\x00\x39\x00\x3c\x00\x3f\x00\x42'\ 87 | b'\x00\x45\x00\x48\x00\x4b\x00\x4e\x00\x51\x00\x54\x00\x57\x00'\ 88 | b'\x5a\x00\x5d\x00\x60\x00\x63\x00\x88\x00\x95\x00\xa0\x00\xad'\ 89 | b'\x00\xc6\x00\xe3\x00\xf0\x00\xfd\x00\x10\x01\x57\x01\x8e\x01'\ 90 | b'\xb1\x01\xd4\x01\xf7\x01\x1a\x02\x2d\x02\x30\x02\x33\x02\x36'\ 91 | b'\x02\x39\x02\x3c\x02\x3f\x02\x42\x02\x45\x02\x48\x02\x4b\x02'\ 92 | b'\x4e\x02\x51\x02\x54\x02\x57\x02\x5a\x02\x5d\x02\x82\x02\x8f'\ 93 | b'\x02\x9a\x02\xa7\x02\xc0\x02\xdd\x02\xea\x02\xf7\x02\x0a\x03'\ 94 | b'\x51\x03\x88\x03\xab\x03\xce\x03\xf1\x03\x14\x04\x27\x04\x2a'\ 95 | b'\x04\x2d\x04\x30\x04\x33\x04\x36\x04\x39\x04\x3c\x04\x3f\x04'\ 96 | b'\x42\x04\x45\x04\x48\x04\x4b\x04\x4e\x04\x51\x04\x54\x04' 97 | 98 | INDEX = memoryview(_index) 99 | FONT = memoryview(_font) 100 | -------------------------------------------------------------------------------- /manifest.py: -------------------------------------------------------------------------------- 1 | include("$(PORT_DIR)/boards/manifest.py") 2 | freeze("modules") 3 | -------------------------------------------------------------------------------- /modules/df.py: -------------------------------------------------------------------------------- 1 | import uos 2 | fs_stat = uos.statvfs('/flash') 3 | fs_size = fs_stat[0] * fs_stat[2] 4 | fs_free = fs_stat[0] * fs_stat[3] 5 | print("File System Size {:,} - Free Space {:,}".format(fs_size, fs_free)) 6 | -------------------------------------------------------------------------------- /modules/focaltouch.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2017 ladyada for adafruit industries 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | # THE SOFTWARE. 22 | """ 23 | `adafruit_focaltouch` 24 | ==================================================== 25 | 26 | CircuitPython driver for common low-cost FocalTech capacitive touch chips. 27 | Currently supports FT6206 & FT6236. 28 | 29 | * Author(s): ladyada 30 | 31 | * adopted for micropython => franz schaefer (mond) 32 | 33 | Implementation Notes 34 | -------------------- 35 | 36 | **Hardware:** 37 | 38 | * Adafruit `2.8" TFT LCD with Cap Touch Breakout Board w/MicroSD Socket 39 | `_ (Product ID: 2090) 40 | 41 | * Adafruit `2.8" TFT Touch Shield for Arduino w/Capacitive Touch 42 | `_ (Product ID: 1947) 43 | 44 | **Software and Dependencies:** 45 | 46 | * Adafruit CircuitPython firmware for the ESP8622 and M0-based boards: 47 | https://github.com/adafruit/circuitpython/releases 48 | * Adafruit's Bus Device library (when using I2C/SPI): 49 | https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 50 | """ 51 | 52 | # imports 53 | 54 | try: 55 | import struct 56 | except ImportError: 57 | import ustruct as struct 58 | 59 | from machine import SoftI2C 60 | from micropython import const 61 | 62 | 63 | _FT6206_DEFAULT_I2C_ADDR = 0x38 64 | 65 | _FT6XXX_REG_DATA = const(0x00) 66 | _FT6XXX_REG_NUMTOUCHES = const(0x02) 67 | _FT6XXX_REG_THRESHHOLD = const(0x80) 68 | _FT6XXX_REG_POINTRATE = const(0x88) 69 | _FT6XXX_REG_LIBH = const(0xA1) 70 | _FT6XXX_REG_LIBL = const(0xA2) 71 | _FT6XXX_REG_CHIPID = const(0xA3) 72 | _FT6XXX_REG_FIRMVERS = const(0xA6) 73 | _FT6XXX_REG_VENDID = const(0xA8) 74 | _FT6XXX_REG_RELEASE = const(0xAF) 75 | 76 | 77 | class FocalTouch: 78 | """ 79 | A driver for the FocalTech capacitive touch sensor. 80 | """ 81 | 82 | _debug = False 83 | chip = None 84 | 85 | def __init__(self, i2c, address=_FT6206_DEFAULT_I2C_ADDR, debug=False): 86 | self.bus = i2c 87 | self.address = address 88 | self._debug = debug 89 | 90 | chip_data = self._read(_FT6XXX_REG_LIBH, 8) 91 | lib_ver, chip_id, _, _, firm_id, _, vend_id = struct.unpack( 92 | ">HBBBBBB", chip_data 93 | ) 94 | 95 | if debug: 96 | print("Vendor ID %02x" % vend_id) 97 | 98 | self.vend_id=vend_id 99 | if chip_id == 0x06: 100 | self.chip = "FT6206" 101 | elif chip_id == 0x64: 102 | self.chip = "FT6236" 103 | elif debug: 104 | print("Chip Id: %02x" % chip_id) 105 | 106 | if debug: 107 | print("Library vers %04X" % lib_ver) 108 | print("Firmware ID %02X" % firm_id) 109 | print("Point rate %d Hz" % self._read(_FT6XXX_REG_POINTRATE, 1)[0]) 110 | print("Thresh %d" % self._read(_FT6XXX_REG_THRESHHOLD, 1)[0]) 111 | 112 | 113 | @property 114 | def touched(self): 115 | """ Returns the number of touches currently detected """ 116 | return self._read(_FT6XXX_REG_NUMTOUCHES, 1)[0] 117 | 118 | # pylint: disable=unused-variable 119 | @property 120 | def touches(self): 121 | """ 122 | Returns a list of touchpoint dicts, with 'x' and 'y' containing the 123 | touch coordinates, and 'id' as the touch # for multitouch tracking 124 | """ 125 | touchpoints = [] 126 | data = self._read(_FT6XXX_REG_DATA, 32) 127 | 128 | for i in range(2): 129 | point_data = data[i * 6 + 3 : i * 6 + 9] 130 | if all([i == 0xFF for i in point_data]): 131 | continue 132 | # print([hex(i) for i in point_data]) 133 | x, y, weight, misc = struct.unpack(">HHBB", point_data) 134 | # print(x, y, weight, misc) 135 | touch_id = y >> 12 136 | x &= 0xFFF 137 | y &= 0xFFF 138 | point = {"x": x, "y": y, "id": touch_id} 139 | touchpoints.append(point) 140 | return touchpoints 141 | 142 | def _read(self, reg, length): 143 | """Returns an array of 'length' bytes from the 'register'""" 144 | result = bytearray(length) 145 | self.bus.readfrom_mem_into(self.address, reg, result) 146 | if self._debug: 147 | print("\t$%02X => %s" % (reg, [hex(i) for i in result])) 148 | return result 149 | 150 | def _write(self, reg, values): 151 | """Writes an array of 'length' bytes to the 'register'""" 152 | values = [(v & 0xFF) for v in values] 153 | self.bus.writeto_mem(self.address,reg,bytes(values)) 154 | if self._debug: 155 | print("\t$%02X <= %s" % (reg, [hex(i) for i in values])) 156 | -------------------------------------------------------------------------------- /modules/greekp.py: -------------------------------------------------------------------------------- 1 | WIDTH = 20 2 | HEIGHT = 20 3 | FIRST = 0x20 4 | LAST = 0x7f 5 | 6 | _font =\ 7 | b'\x00\x4e\x56\x0b\x50\x55\x52\x4d\x52\x52\x20\x52\x53\x4d\x53'\ 8 | b'\x52\x20\x52\x52\x55\x52\x56\x53\x56\x53\x55\x52\x55\x05\x4e'\ 9 | b'\x56\x50\x4d\x50\x51\x20\x52\x54\x4d\x54\x51\x0b\x4d\x58\x52'\ 10 | b'\x4c\x50\x57\x20\x52\x55\x4c\x53\x57\x20\x52\x4f\x50\x56\x50'\ 11 | b'\x20\x52\x4f\x53\x56\x53\x0f\x4d\x57\x55\x4e\x53\x4d\x51\x4d'\ 12 | b'\x4f\x4e\x4f\x50\x51\x51\x54\x52\x55\x53\x55\x55\x53\x56\x51'\ 13 | b'\x56\x4f\x55\x20\x52\x52\x4c\x52\x57\x19\x4a\x5a\x58\x4b\x4c'\ 14 | b'\x58\x20\x52\x4f\x4b\x50\x4c\x50\x4e\x4f\x4f\x4d\x4f\x4c\x4e'\ 15 | b'\x4c\x4c\x4d\x4b\x4f\x4b\x53\x4c\x56\x4c\x58\x4b\x20\x52\x55'\ 16 | b'\x54\x54\x55\x54\x57\x55\x58\x57\x58\x58\x57\x58\x55\x57\x54'\ 17 | b'\x55\x54\x14\x4c\x58\x56\x52\x55\x52\x54\x53\x53\x55\x52\x56'\ 18 | b'\x4f\x56\x4e\x55\x4e\x53\x4f\x52\x52\x51\x53\x50\x53\x4e\x52'\ 19 | b'\x4d\x50\x4d\x4f\x4e\x4f\x50\x51\x53\x53\x55\x55\x56\x56\x56'\ 20 | b'\x06\x50\x55\x53\x4e\x52\x4e\x52\x4d\x53\x4d\x53\x4f\x52\x51'\ 21 | b'\x06\x4f\x56\x54\x4c\x52\x4e\x51\x50\x51\x53\x52\x55\x54\x57'\ 22 | b'\x06\x4e\x55\x50\x4c\x52\x4e\x53\x50\x53\x53\x52\x55\x50\x57'\ 23 | b'\x08\x4d\x57\x52\x4a\x52\x50\x20\x52\x4f\x4b\x55\x4f\x20\x52'\ 24 | b'\x55\x4b\x4f\x4f\x05\x4c\x58\x52\x4e\x52\x56\x20\x52\x4e\x52'\ 25 | b'\x56\x52\x06\x50\x55\x53\x56\x52\x56\x52\x55\x53\x55\x53\x57'\ 26 | b'\x52\x59\x02\x4c\x58\x4e\x52\x56\x52\x05\x50\x55\x52\x55\x52'\ 27 | b'\x56\x53\x56\x53\x55\x52\x55\x02\x4d\x57\x56\x4c\x4e\x57\x0b'\ 28 | b'\x4d\x57\x52\x4d\x50\x4e\x4f\x50\x4f\x53\x50\x55\x52\x56\x54'\ 29 | b'\x55\x55\x53\x55\x50\x54\x4e\x52\x4d\x03\x4d\x57\x50\x4f\x52'\ 30 | b'\x4d\x52\x56\x08\x4d\x57\x4f\x4e\x51\x4d\x53\x4d\x55\x4e\x55'\ 31 | b'\x50\x54\x52\x4f\x56\x55\x56\x0e\x4d\x57\x4f\x4e\x51\x4d\x53'\ 32 | b'\x4d\x55\x4e\x55\x50\x53\x51\x20\x52\x52\x51\x53\x51\x55\x52'\ 33 | b'\x55\x55\x53\x56\x51\x56\x4f\x55\x06\x4d\x57\x53\x4d\x53\x56'\ 34 | b'\x20\x52\x53\x4d\x4e\x53\x56\x53\x0d\x4d\x57\x50\x4d\x4f\x51'\ 35 | b'\x51\x50\x52\x50\x54\x51\x55\x53\x54\x55\x52\x56\x51\x56\x4f'\ 36 | b'\x55\x20\x52\x50\x4d\x54\x4d\x0d\x4d\x57\x54\x4d\x52\x4d\x50'\ 37 | b'\x4e\x4f\x50\x4f\x53\x50\x55\x52\x56\x54\x55\x55\x53\x54\x51'\ 38 | b'\x52\x50\x50\x51\x4f\x53\x05\x4d\x57\x55\x4d\x51\x56\x20\x52'\ 39 | b'\x4f\x4d\x55\x4d\x12\x4d\x57\x51\x4d\x4f\x4e\x4f\x50\x51\x51'\ 40 | b'\x53\x51\x55\x50\x55\x4e\x53\x4d\x51\x4d\x20\x52\x51\x51\x4f'\ 41 | b'\x52\x4f\x55\x51\x56\x53\x56\x55\x55\x55\x52\x53\x51\x0d\x4d'\ 42 | b'\x57\x55\x50\x54\x52\x52\x53\x50\x52\x4f\x50\x50\x4e\x52\x4d'\ 43 | b'\x54\x4e\x55\x50\x55\x53\x54\x55\x52\x56\x50\x56\x0b\x50\x55'\ 44 | b'\x52\x50\x52\x51\x53\x51\x53\x50\x52\x50\x20\x52\x52\x55\x52'\ 45 | b'\x56\x53\x56\x53\x55\x52\x55\x0c\x50\x55\x52\x50\x52\x51\x53'\ 46 | b'\x51\x53\x50\x52\x50\x20\x52\x53\x56\x52\x56\x52\x55\x53\x55'\ 47 | b'\x53\x57\x52\x59\x03\x4a\x5a\x57\x4c\x4d\x52\x57\x58\x05\x4c'\ 48 | b'\x58\x4e\x50\x56\x50\x20\x52\x4e\x54\x56\x54\x03\x4a\x5a\x4d'\ 49 | b'\x4c\x57\x52\x4d\x58\x10\x4e\x57\x50\x4e\x52\x4d\x53\x4d\x55'\ 50 | b'\x4e\x55\x50\x52\x51\x52\x52\x53\x52\x53\x51\x55\x50\x20\x52'\ 51 | b'\x52\x55\x52\x56\x53\x56\x53\x55\x52\x55\x1c\x4a\x5b\x55\x50'\ 52 | b'\x53\x4f\x51\x4f\x50\x51\x50\x52\x51\x54\x53\x54\x55\x53\x20'\ 53 | b'\x52\x55\x4f\x55\x53\x56\x54\x58\x54\x59\x52\x59\x51\x58\x4e'\ 54 | b'\x56\x4c\x53\x4b\x52\x4b\x4f\x4c\x4d\x4e\x4c\x51\x4c\x52\x4d'\ 55 | b'\x55\x4f\x57\x52\x58\x53\x58\x56\x57\x08\x4d\x57\x52\x4d\x4e'\ 56 | b'\x56\x20\x52\x52\x4d\x56\x56\x20\x52\x50\x53\x54\x53\x0f\x4d'\ 57 | b'\x57\x4f\x4d\x4f\x56\x20\x52\x4f\x4d\x53\x4d\x55\x4e\x55\x50'\ 58 | b'\x53\x51\x20\x52\x4f\x51\x53\x51\x55\x52\x55\x55\x53\x56\x4f'\ 59 | b'\x56\x05\x4d\x56\x4f\x4d\x4f\x56\x20\x52\x4f\x4d\x55\x4d\x08'\ 60 | b'\x4d\x57\x52\x4d\x4e\x56\x20\x52\x52\x4d\x56\x56\x20\x52\x4e'\ 61 | b'\x56\x56\x56\x0b\x4d\x57\x4f\x4d\x4f\x56\x20\x52\x4f\x4d\x55'\ 62 | b'\x4d\x20\x52\x4f\x51\x53\x51\x20\x52\x4f\x56\x55\x56\x08\x4d'\ 63 | b'\x57\x55\x4d\x4f\x56\x20\x52\x4f\x4d\x55\x4d\x20\x52\x4f\x56'\ 64 | b'\x55\x56\x08\x4d\x57\x4f\x4d\x4f\x56\x20\x52\x55\x4d\x55\x56'\ 65 | b'\x20\x52\x4f\x51\x55\x51\x13\x4d\x58\x52\x4d\x50\x4e\x4f\x50'\ 66 | b'\x4f\x53\x50\x55\x52\x56\x53\x56\x55\x55\x56\x53\x56\x50\x55'\ 67 | b'\x4e\x53\x4d\x52\x4d\x20\x52\x51\x51\x54\x52\x20\x52\x54\x51'\ 68 | b'\x51\x52\x02\x50\x54\x52\x4d\x52\x56\x08\x4d\x57\x4f\x4d\x4f'\ 69 | b'\x56\x20\x52\x55\x4d\x4f\x53\x20\x52\x51\x51\x55\x56\x05\x4d'\ 70 | b'\x57\x52\x4d\x4e\x56\x20\x52\x52\x4d\x56\x56\x0b\x4c\x58\x4e'\ 71 | b'\x4d\x4e\x56\x20\x52\x4e\x4d\x52\x56\x20\x52\x56\x4d\x52\x56'\ 72 | b'\x20\x52\x56\x4d\x56\x56\x08\x4d\x57\x4f\x4d\x4f\x56\x20\x52'\ 73 | b'\x4f\x4d\x55\x56\x20\x52\x55\x4d\x55\x56\x0b\x4d\x57\x4f\x4d'\ 74 | b'\x55\x4d\x20\x52\x50\x51\x54\x52\x20\x52\x54\x51\x50\x52\x20'\ 75 | b'\x52\x4f\x56\x55\x56\x0d\x4d\x58\x52\x4d\x50\x4e\x4f\x50\x4f'\ 76 | b'\x53\x50\x55\x52\x56\x53\x56\x55\x55\x56\x53\x56\x50\x55\x4e'\ 77 | b'\x53\x4d\x52\x4d\x08\x4d\x57\x4f\x4d\x4f\x56\x20\x52\x55\x4d'\ 78 | b'\x55\x56\x20\x52\x4f\x4d\x55\x4d\x09\x4d\x57\x4f\x4d\x4f\x56'\ 79 | b'\x20\x52\x4f\x4d\x53\x4d\x55\x4e\x55\x51\x53\x52\x4f\x52\x09'\ 80 | b'\x4d\x57\x4f\x4d\x52\x51\x4f\x56\x20\x52\x4f\x4d\x55\x4d\x20'\ 81 | b'\x52\x4f\x56\x55\x56\x05\x4d\x57\x52\x4d\x52\x56\x20\x52\x4e'\ 82 | b'\x4d\x56\x4d\x0e\x4d\x57\x4e\x4f\x4e\x4e\x4f\x4d\x50\x4d\x51'\ 83 | b'\x4e\x52\x50\x52\x56\x20\x52\x56\x4f\x56\x4e\x55\x4d\x54\x4d'\ 84 | b'\x53\x4e\x52\x50\x0c\x4c\x58\x52\x4d\x52\x56\x20\x52\x50\x4f'\ 85 | b'\x4e\x50\x4e\x53\x50\x54\x54\x54\x56\x53\x56\x50\x54\x4f\x50'\ 86 | b'\x4f\x05\x4d\x57\x4f\x4d\x55\x56\x20\x52\x55\x4d\x4f\x56\x0b'\ 87 | b'\x4c\x58\x52\x4d\x52\x56\x20\x52\x4e\x4f\x4f\x50\x4f\x53\x51'\ 88 | b'\x54\x53\x54\x55\x53\x55\x50\x56\x4f\x0c\x4d\x58\x4f\x56\x51'\ 89 | b'\x56\x4f\x52\x4f\x50\x50\x4e\x52\x4d\x53\x4d\x55\x4e\x56\x50'\ 90 | b'\x56\x52\x54\x56\x56\x56\x00\x4e\x56\x00\x4e\x56\x0b\x4d\x57'\ 91 | b'\x50\x48\x50\x5c\x20\x52\x51\x48\x51\x5c\x20\x52\x50\x48\x55'\ 92 | b'\x48\x20\x52\x50\x5c\x55\x5c\x02\x4d\x57\x4d\x4d\x57\x57\x0b'\ 93 | b'\x4d\x57\x53\x48\x53\x5c\x20\x52\x54\x48\x54\x5c\x20\x52\x4f'\ 94 | b'\x48\x54\x48\x20\x52\x4f\x5c\x54\x5c\x0c\x4d\x57\x52\x4d\x52'\ 95 | b'\x58\x20\x52\x4f\x50\x50\x4f\x52\x4c\x54\x4f\x55\x50\x20\x52'\ 96 | b'\x50\x4f\x52\x4d\x54\x4f\x02\x4d\x57\x4d\x58\x57\x58\x06\x50'\ 97 | b'\x55\x53\x4d\x52\x4f\x52\x51\x53\x51\x53\x50\x52\x50\x08\x4d'\ 98 | b'\x57\x52\x4d\x4e\x56\x20\x52\x52\x4d\x56\x56\x20\x52\x50\x53'\ 99 | b'\x54\x53\x0f\x4d\x57\x4f\x4d\x4f\x56\x20\x52\x4f\x4d\x53\x4d'\ 100 | b'\x55\x4e\x55\x50\x53\x51\x20\x52\x4f\x51\x53\x51\x55\x52\x55'\ 101 | b'\x55\x53\x56\x4f\x56\x05\x4d\x56\x4f\x4d\x4f\x56\x20\x52\x4f'\ 102 | b'\x4d\x55\x4d\x08\x4d\x57\x52\x4d\x4e\x56\x20\x52\x52\x4d\x56'\ 103 | b'\x56\x20\x52\x4e\x56\x56\x56\x0b\x4d\x57\x4f\x4d\x4f\x56\x20'\ 104 | b'\x52\x4f\x4d\x55\x4d\x20\x52\x4f\x51\x53\x51\x20\x52\x4f\x56'\ 105 | b'\x55\x56\x08\x4d\x57\x55\x4d\x4f\x56\x20\x52\x4f\x4d\x55\x4d'\ 106 | b'\x20\x52\x4f\x56\x55\x56\x08\x4d\x57\x4f\x4d\x4f\x56\x20\x52'\ 107 | b'\x55\x4d\x55\x56\x20\x52\x4f\x51\x55\x51\x13\x4d\x58\x52\x4d'\ 108 | b'\x50\x4e\x4f\x50\x4f\x53\x50\x55\x52\x56\x53\x56\x55\x55\x56'\ 109 | b'\x53\x56\x50\x55\x4e\x53\x4d\x52\x4d\x20\x52\x51\x51\x54\x52'\ 110 | b'\x20\x52\x54\x51\x51\x52\x02\x50\x54\x52\x4d\x52\x56\x08\x4d'\ 111 | b'\x57\x4f\x4d\x4f\x56\x20\x52\x55\x4d\x4f\x53\x20\x52\x51\x51'\ 112 | b'\x55\x56\x05\x4d\x57\x52\x4d\x4e\x56\x20\x52\x52\x4d\x56\x56'\ 113 | b'\x0b\x4c\x58\x4e\x4d\x4e\x56\x20\x52\x4e\x4d\x52\x56\x20\x52'\ 114 | b'\x56\x4d\x52\x56\x20\x52\x56\x4d\x56\x56\x08\x4d\x57\x4f\x4d'\ 115 | b'\x4f\x56\x20\x52\x4f\x4d\x55\x56\x20\x52\x55\x4d\x55\x56\x0b'\ 116 | b'\x4d\x57\x4f\x4d\x55\x4d\x20\x52\x50\x51\x54\x52\x20\x52\x54'\ 117 | b'\x51\x50\x52\x20\x52\x4f\x56\x55\x56\x0d\x4d\x58\x52\x4d\x50'\ 118 | b'\x4e\x4f\x50\x4f\x53\x50\x55\x52\x56\x53\x56\x55\x55\x56\x53'\ 119 | b'\x56\x50\x55\x4e\x53\x4d\x52\x4d\x08\x4d\x57\x4f\x4d\x4f\x56'\ 120 | b'\x20\x52\x55\x4d\x55\x56\x20\x52\x4f\x4d\x55\x4d\x09\x4d\x57'\ 121 | b'\x4f\x4d\x4f\x56\x20\x52\x4f\x4d\x53\x4d\x55\x4e\x55\x51\x53'\ 122 | b'\x52\x4f\x52\x09\x4d\x57\x4f\x4d\x52\x51\x4f\x56\x20\x52\x4f'\ 123 | b'\x4d\x55\x4d\x20\x52\x4f\x56\x55\x56\x05\x4d\x57\x52\x4d\x52'\ 124 | b'\x56\x20\x52\x4e\x4d\x56\x4d\x0e\x4d\x57\x4e\x4f\x4e\x4e\x4f'\ 125 | b'\x4d\x50\x4d\x51\x4e\x52\x50\x52\x56\x20\x52\x56\x4f\x56\x4e'\ 126 | b'\x55\x4d\x54\x4d\x53\x4e\x52\x50\x0c\x4c\x58\x52\x4d\x52\x56'\ 127 | b'\x20\x52\x50\x4f\x4e\x50\x4e\x53\x50\x54\x54\x54\x56\x53\x56'\ 128 | b'\x50\x54\x4f\x50\x4f\x05\x4d\x57\x4f\x4d\x55\x56\x20\x52\x55'\ 129 | b'\x4d\x4f\x56\x0b\x4c\x58\x52\x4d\x52\x56\x20\x52\x4e\x4f\x4f'\ 130 | b'\x50\x4f\x53\x51\x54\x53\x54\x55\x53\x55\x50\x56\x4f\x0c\x4d'\ 131 | b'\x58\x4f\x56\x51\x56\x4f\x52\x4f\x50\x50\x4e\x52\x4d\x53\x4d'\ 132 | b'\x55\x4e\x56\x50\x56\x52\x54\x56\x56\x56\x00\x4e\x56\x00\x4e'\ 133 | b'\x56\x25\x4c\x57\x53\x48\x51\x49\x50\x4a\x50\x4c\x52\x4e\x53'\ 134 | b'\x50\x20\x52\x51\x49\x50\x4c\x20\x52\x53\x4e\x52\x51\x20\x52'\ 135 | b'\x50\x4a\x51\x4c\x53\x4e\x53\x50\x52\x51\x50\x52\x52\x53\x53'\ 136 | b'\x54\x53\x56\x51\x58\x50\x5a\x20\x52\x52\x53\x53\x56\x20\x52'\ 137 | b'\x50\x58\x51\x5b\x20\x52\x53\x54\x52\x56\x50\x58\x50\x5a\x51'\ 138 | b'\x5b\x53\x5c\x02\x50\x54\x52\x4c\x52\x57\x25\x4d\x58\x51\x48'\ 139 | b'\x53\x49\x54\x4a\x54\x4c\x52\x4e\x51\x50\x20\x52\x53\x49\x54'\ 140 | b'\x4c\x20\x52\x51\x4e\x52\x51\x20\x52\x54\x4a\x53\x4c\x51\x4e'\ 141 | b'\x51\x50\x52\x51\x54\x52\x52\x53\x51\x54\x51\x56\x53\x58\x54'\ 142 | b'\x5a\x20\x52\x52\x53\x51\x56\x20\x52\x54\x58\x53\x5b\x20\x52'\ 143 | b'\x51\x54\x52\x56\x54\x58\x54\x5a\x53\x5b\x51\x5c\x0f\x4a\x5a'\ 144 | b'\x4c\x54\x4c\x52\x4d\x50\x4f\x50\x55\x53\x57\x53\x58\x52\x20'\ 145 | b'\x52\x4c\x52\x4d\x51\x4f\x51\x55\x54\x57\x54\x58\x52\x58\x50'\ 146 | b'\x09\x4e\x56\x51\x4d\x50\x4e\x50\x50\x51\x51\x53\x51\x54\x50'\ 147 | b'\x54\x4e\x53\x4d\x51\x4d' 148 | 149 | _index =\ 150 | b'\x00\x00\x03\x00\x1c\x00\x29\x00\x42\x00\x63\x00\x98\x00\xc3'\ 151 | b'\x00\xd2\x00\xe1\x00\xf0\x00\x03\x01\x10\x01\x1f\x01\x26\x01'\ 152 | b'\x33\x01\x3a\x01\x53\x01\x5c\x01\x6f\x01\x8e\x01\x9d\x01\xba'\ 153 | b'\x01\xd7\x01\xe4\x01\x0b\x02\x28\x02\x41\x02\x5c\x02\x65\x02'\ 154 | b'\x72\x02\x7b\x02\x9e\x02\xd9\x02\xec\x02\x0d\x03\x1a\x03\x2d'\ 155 | b'\x03\x46\x03\x59\x03\x6c\x03\x95\x03\x9c\x03\xaf\x03\xbc\x03'\ 156 | b'\xd5\x03\xe8\x03\x01\x04\x1e\x04\x31\x04\x46\x04\x5b\x04\x68'\ 157 | b'\x04\x87\x04\xa2\x04\xaf\x04\xc8\x04\xe3\x04\xe6\x04\xe9\x04'\ 158 | b'\x02\x05\x09\x05\x22\x05\x3d\x05\x44\x05\x53\x05\x66\x05\x87'\ 159 | b'\x05\x94\x05\xa7\x05\xc0\x05\xd3\x05\xe6\x05\x0f\x06\x16\x06'\ 160 | b'\x29\x06\x36\x06\x4f\x06\x62\x06\x7b\x06\x98\x06\xab\x06\xc0'\ 161 | b'\x06\xd5\x06\xe2\x06\x01\x07\x1c\x07\x29\x07\x42\x07\x5d\x07'\ 162 | b'\x60\x07\x63\x07\xb0\x07\xb7\x07\x04\x08\x25\x08' 163 | 164 | INDEX = memoryview(_index) 165 | FONT = memoryview(_font) 166 | -------------------------------------------------------------------------------- /modules/marker.py: -------------------------------------------------------------------------------- 1 | WIDTH = 26 2 | HEIGHT = 26 3 | FIRST = 0x20 4 | LAST = 0x7f 5 | 6 | _font =\ 7 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 8 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 9 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 10 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 11 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 12 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a'\ 13 | b'\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x11\x4b\x59\x51\x4b\x4e'\ 14 | b'\x4c\x4c\x4e\x4b\x51\x4b\x53\x4c\x56\x4e\x58\x51\x59\x53\x59'\ 15 | b'\x56\x58\x58\x56\x59\x53\x59\x51\x58\x4e\x56\x4c\x53\x4b\x51'\ 16 | b'\x4b\x05\x4c\x58\x4c\x4c\x4c\x58\x58\x58\x58\x4c\x4c\x4c\x04'\ 17 | b'\x4b\x59\x52\x4a\x4b\x56\x59\x56\x52\x4a\x05\x4c\x58\x52\x48'\ 18 | b'\x4c\x52\x52\x5c\x58\x52\x52\x48\x0b\x4a\x5a\x52\x49\x50\x4f'\ 19 | b'\x4a\x4f\x4f\x53\x4d\x59\x52\x55\x57\x59\x55\x53\x5a\x4f\x54'\ 20 | b'\x4f\x52\x49\x0d\x4c\x58\x50\x4c\x50\x50\x4c\x50\x4c\x54\x50'\ 21 | b'\x54\x50\x58\x54\x58\x54\x54\x58\x54\x58\x50\x54\x50\x54\x4c'\ 22 | b'\x50\x4c\x05\x4b\x59\x52\x4b\x52\x59\x20\x52\x4b\x52\x59\x52'\ 23 | b'\x05\x4d\x57\x4d\x4d\x57\x57\x20\x52\x57\x4d\x4d\x57\x08\x4d'\ 24 | b'\x57\x52\x4c\x52\x58\x20\x52\x4d\x4f\x57\x55\x20\x52\x57\x4f'\ 25 | b'\x4d\x55\x22\x4e\x56\x51\x4e\x4f\x4f\x4e\x51\x4e\x53\x4f\x55'\ 26 | b'\x51\x56\x53\x56\x55\x55\x56\x53\x56\x51\x55\x4f\x53\x4e\x51'\ 27 | b'\x4e\x20\x52\x4f\x51\x4f\x53\x20\x52\x50\x50\x50\x54\x20\x52'\ 28 | b'\x51\x4f\x51\x55\x20\x52\x52\x4f\x52\x55\x20\x52\x53\x4f\x53'\ 29 | b'\x55\x20\x52\x54\x50\x54\x54\x20\x52\x55\x51\x55\x53\x1a\x4e'\ 30 | b'\x56\x4e\x4e\x4e\x56\x56\x56\x56\x4e\x4e\x4e\x20\x52\x4f\x4f'\ 31 | b'\x4f\x55\x20\x52\x50\x4f\x50\x55\x20\x52\x51\x4f\x51\x55\x20'\ 32 | b'\x52\x52\x4f\x52\x55\x20\x52\x53\x4f\x53\x55\x20\x52\x54\x4f'\ 33 | b'\x54\x55\x20\x52\x55\x4f\x55\x55\x10\x4d\x57\x52\x4c\x4d\x55'\ 34 | b'\x57\x55\x52\x4c\x20\x52\x52\x4f\x4f\x54\x20\x52\x52\x4f\x55'\ 35 | b'\x54\x20\x52\x52\x52\x51\x54\x20\x52\x52\x52\x53\x54\x10\x4c'\ 36 | b'\x55\x4c\x52\x55\x57\x55\x4d\x4c\x52\x20\x52\x4f\x52\x54\x55'\ 37 | b'\x20\x52\x4f\x52\x54\x4f\x20\x52\x52\x52\x54\x53\x20\x52\x52'\ 38 | b'\x52\x54\x51\x10\x4d\x57\x52\x58\x57\x4f\x4d\x4f\x52\x58\x20'\ 39 | b'\x52\x52\x55\x55\x50\x20\x52\x52\x55\x4f\x50\x20\x52\x52\x52'\ 40 | b'\x53\x50\x20\x52\x52\x52\x51\x50\x10\x4f\x58\x58\x52\x4f\x4d'\ 41 | b'\x4f\x57\x58\x52\x20\x52\x55\x52\x50\x4f\x20\x52\x55\x52\x50'\ 42 | b'\x55\x20\x52\x52\x52\x50\x51\x20\x52\x52\x52\x50\x53\x08\x44'\ 43 | b'\x60\x44\x52\x60\x52\x20\x52\x44\x52\x52\x62\x20\x52\x60\x52'\ 44 | b'\x52\x62\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00'\ 45 | b'\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00'\ 46 | b'\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00'\ 47 | b'\x4a\x5a\x00\x4a\x5a\x11\x4b\x59\x51\x4b\x4e\x4c\x4c\x4e\x4b'\ 48 | b'\x51\x4b\x53\x4c\x56\x4e\x58\x51\x59\x53\x59\x56\x58\x58\x56'\ 49 | b'\x59\x53\x59\x51\x58\x4e\x56\x4c\x53\x4b\x51\x4b\x05\x4c\x58'\ 50 | b'\x4c\x4c\x4c\x58\x58\x58\x58\x4c\x4c\x4c\x04\x4b\x59\x52\x4a'\ 51 | b'\x4b\x56\x59\x56\x52\x4a\x05\x4c\x58\x52\x48\x4c\x52\x52\x5c'\ 52 | b'\x58\x52\x52\x48\x0b\x4a\x5a\x52\x49\x50\x4f\x4a\x4f\x4f\x53'\ 53 | b'\x4d\x59\x52\x55\x57\x59\x55\x53\x5a\x4f\x54\x4f\x52\x49\x0d'\ 54 | b'\x4c\x58\x50\x4c\x50\x50\x4c\x50\x4c\x54\x50\x54\x50\x58\x54'\ 55 | b'\x58\x54\x54\x58\x54\x58\x50\x54\x50\x54\x4c\x50\x4c\x05\x4b'\ 56 | b'\x59\x52\x4b\x52\x59\x20\x52\x4b\x52\x59\x52\x05\x4d\x57\x4d'\ 57 | b'\x4d\x57\x57\x20\x52\x57\x4d\x4d\x57\x08\x4d\x57\x52\x4c\x52'\ 58 | b'\x58\x20\x52\x4d\x4f\x57\x55\x20\x52\x57\x4f\x4d\x55\x22\x4e'\ 59 | b'\x56\x51\x4e\x4f\x4f\x4e\x51\x4e\x53\x4f\x55\x51\x56\x53\x56'\ 60 | b'\x55\x55\x56\x53\x56\x51\x55\x4f\x53\x4e\x51\x4e\x20\x52\x4f'\ 61 | b'\x51\x4f\x53\x20\x52\x50\x50\x50\x54\x20\x52\x51\x4f\x51\x55'\ 62 | b'\x20\x52\x52\x4f\x52\x55\x20\x52\x53\x4f\x53\x55\x20\x52\x54'\ 63 | b'\x50\x54\x54\x20\x52\x55\x51\x55\x53\x1a\x4e\x56\x4e\x4e\x4e'\ 64 | b'\x56\x56\x56\x56\x4e\x4e\x4e\x20\x52\x4f\x4f\x4f\x55\x20\x52'\ 65 | b'\x50\x4f\x50\x55\x20\x52\x51\x4f\x51\x55\x20\x52\x52\x4f\x52'\ 66 | b'\x55\x20\x52\x53\x4f\x53\x55\x20\x52\x54\x4f\x54\x55\x20\x52'\ 67 | b'\x55\x4f\x55\x55\x10\x4d\x57\x52\x4c\x4d\x55\x57\x55\x52\x4c'\ 68 | b'\x20\x52\x52\x4f\x4f\x54\x20\x52\x52\x4f\x55\x54\x20\x52\x52'\ 69 | b'\x52\x51\x54\x20\x52\x52\x52\x53\x54\x10\x4c\x55\x4c\x52\x55'\ 70 | b'\x57\x55\x4d\x4c\x52\x20\x52\x4f\x52\x54\x55\x20\x52\x4f\x52'\ 71 | b'\x54\x4f\x20\x52\x52\x52\x54\x53\x20\x52\x52\x52\x54\x51\x10'\ 72 | b'\x4d\x57\x52\x58\x57\x4f\x4d\x4f\x52\x58\x20\x52\x52\x55\x55'\ 73 | b'\x50\x20\x52\x52\x55\x4f\x50\x20\x52\x52\x52\x53\x50\x20\x52'\ 74 | b'\x52\x52\x51\x50\x10\x4f\x58\x58\x52\x4f\x4d\x4f\x57\x58\x52'\ 75 | b'\x20\x52\x55\x52\x50\x4f\x20\x52\x55\x52\x50\x55\x20\x52\x52'\ 76 | b'\x52\x50\x51\x20\x52\x52\x52\x50\x53\x08\x44\x60\x44\x52\x60'\ 77 | b'\x52\x20\x52\x44\x52\x52\x62\x20\x52\x60\x52\x52\x62\x00\x4a'\ 78 | b'\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a'\ 79 | b'\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a'\ 80 | b'\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a\x5a\x00\x4a'\ 81 | b'\x5a' 82 | 83 | _index =\ 84 | b'\x00\x00\x03\x00\x06\x00\x09\x00\x0c\x00\x0f\x00\x12\x00\x15'\ 85 | b'\x00\x18\x00\x1b\x00\x1e\x00\x21\x00\x24\x00\x27\x00\x2a\x00'\ 86 | b'\x2d\x00\x30\x00\x33\x00\x36\x00\x39\x00\x3c\x00\x3f\x00\x42'\ 87 | b'\x00\x45\x00\x48\x00\x4b\x00\x4e\x00\x51\x00\x54\x00\x57\x00'\ 88 | b'\x5a\x00\x5d\x00\x60\x00\x63\x00\x88\x00\x95\x00\xa0\x00\xad'\ 89 | b'\x00\xc6\x00\xe3\x00\xf0\x00\xfd\x00\x10\x01\x57\x01\x8e\x01'\ 90 | b'\xb1\x01\xd4\x01\xf7\x01\x1a\x02\x2d\x02\x30\x02\x33\x02\x36'\ 91 | b'\x02\x39\x02\x3c\x02\x3f\x02\x42\x02\x45\x02\x48\x02\x4b\x02'\ 92 | b'\x4e\x02\x51\x02\x54\x02\x57\x02\x5a\x02\x5d\x02\x82\x02\x8f'\ 93 | b'\x02\x9a\x02\xa7\x02\xc0\x02\xdd\x02\xea\x02\xf7\x02\x0a\x03'\ 94 | b'\x51\x03\x88\x03\xab\x03\xce\x03\xf1\x03\x14\x04\x27\x04\x2a'\ 95 | b'\x04\x2d\x04\x30\x04\x33\x04\x36\x04\x39\x04\x3c\x04\x3f\x04'\ 96 | b'\x42\x04\x45\x04\x48\x04\x4b\x04\x4e\x04\x51\x04\x54\x04' 97 | 98 | INDEX = memoryview(_index) 99 | FONT = memoryview(_font) 100 | -------------------------------------------------------------------------------- /modules/mf.py: -------------------------------------------------------------------------------- 1 | import gc 2 | 3 | print("Allocating 1K bytes until memory is full... ", end='') 4 | memory = [] 5 | i = 0 6 | gc.collect() 7 | 8 | try: 9 | while True: 10 | memory.append(bytearray(1024)) 11 | i += 1 12 | 13 | except MemoryError: 14 | gc.collect() 15 | print(f'{i}K bytes Allocated.') 16 | -------------------------------------------------------------------------------- /modules/sdcard.py: -------------------------------------------------------------------------------- 1 | """ 2 | MicroPython driver for SD cards using SPI bus. 3 | 4 | Requires an SPI bus and a CS pin. Provides readblocks and writeblocks 5 | methods so the device can be mounted as a filesystem. 6 | 7 | Example usage on pyboard: 8 | 9 | import pyb, sdcard, os 10 | sd = sdcard.SDCard(pyb.SPI(1), pyb.Pin.board.X5) 11 | pyb.mount(sd, '/sd2') 12 | os.listdir('/') 13 | 14 | Example usage on ESP8266: 15 | 16 | import machine, sdcard, os 17 | sd = sdcard.SDCard(machine.SPI(1), machine.Pin(15)) 18 | os.mount(sd, '/sd') 19 | os.listdir('/') 20 | 21 | """ 22 | 23 | from micropython import const 24 | import time 25 | 26 | 27 | _CMD_TIMEOUT = const(1000) # PGH (was 100) 28 | 29 | _R1_IDLE_STATE = const(1 << 0) 30 | # R1_ERASE_RESET = const(1 << 1) 31 | _R1_ILLEGAL_COMMAND = const(1 << 2) 32 | # R1_COM_CRC_ERROR = const(1 << 3) 33 | # R1_ERASE_SEQUENCE_ERROR = const(1 << 4) 34 | # R1_ADDRESS_ERROR = const(1 << 5) 35 | # R1_PARAMETER_ERROR = const(1 << 6) 36 | _TOKEN_CMD25 = const(0xFC) 37 | _TOKEN_STOP_TRAN = const(0xFD) 38 | _TOKEN_DATA = const(0xFE) 39 | 40 | 41 | class SDCard: 42 | def __init__(self, spi, cs): 43 | self.spi = spi 44 | self.cs = cs 45 | 46 | self.cmdbuf = bytearray(6) 47 | self.dummybuf = bytearray(512) 48 | self.tokenbuf = bytearray(1) 49 | for i in range(512): 50 | self.dummybuf[i] = 0xFF 51 | self.dummybuf_memoryview = memoryview(self.dummybuf) 52 | 53 | # initialise the card 54 | self.init_card() 55 | 56 | def init_spi(self, baudrate): 57 | try: 58 | master = self.spi.MASTER 59 | except AttributeError: 60 | # on ESP8266 61 | self.spi.init(baudrate=baudrate, phase=0, polarity=0) 62 | else: 63 | # on pyboard 64 | self.spi.init(master, baudrate=baudrate, phase=0, polarity=0) 65 | 66 | def init_card(self): 67 | # init CS pin 68 | self.cs.init(self.cs.OUT, value=1) 69 | 70 | # init SPI bus; use low data rate for initialisation 71 | self.init_spi(100000) 72 | 73 | # clock card at least 100 cycles with cs high 74 | for i in range(16): 75 | self.spi.write(b"\xff") 76 | 77 | # CMD0: init card; should return _R1_IDLE_STATE (allow 5 attempts) 78 | for _ in range(5): 79 | if self.cmd(0, 0, 0x95) == _R1_IDLE_STATE: 80 | break 81 | else: 82 | raise OSError("no SD card") 83 | 84 | # CMD8: determine card version 85 | r = self.cmd(8, 0x01AA, 0x87, 4) 86 | if r == _R1_IDLE_STATE: 87 | self.init_card_v2() 88 | elif r == (_R1_IDLE_STATE | _R1_ILLEGAL_COMMAND): 89 | self.init_card_v1() 90 | else: 91 | raise OSError("couldn't determine SD card version") 92 | 93 | # get the number of sectors 94 | # CMD9: response R2 (R1 byte + 16-byte block read) 95 | if self.cmd(9, 0, 0, 0, False) != 0: 96 | raise OSError("no response from SD card") 97 | csd = bytearray(16) 98 | self.readinto(csd) 99 | if csd[0] & 0xC0 == 0x40: # CSD version 2.0 100 | self.sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024 101 | elif csd[0] & 0xC0 == 0x00: # CSD version 1.0 (old, <=2GB) 102 | c_size = csd[6] & 0b11 | csd[7] << 2 | (csd[8] & 0b11000000) << 4 103 | c_size_mult = ((csd[9] & 0b11) << 1) | csd[10] >> 7 104 | self.sectors = (c_size + 1) * (2 ** (c_size_mult + 2)) 105 | else: 106 | raise OSError("SD card CSD format not supported") 107 | # print('sectors', self.sectors) 108 | 109 | # CMD16: set block length to 512 bytes 110 | if self.cmd(16, 512, 0) != 0: 111 | raise OSError("can't set 512 block size") 112 | 113 | # set to high data rate now that it's initialised 114 | self.init_spi(30000000) 115 | 116 | def init_card_v1(self): 117 | for i in range(_CMD_TIMEOUT): 118 | self.cmd(55, 0, 0) 119 | if self.cmd(41, 0, 0) == 0: 120 | self.cdv = 512 121 | # print("[SDCard] v1 card") 122 | return 123 | raise OSError("timeout waiting for v1 card") 124 | 125 | def init_card_v2(self): 126 | for i in range(_CMD_TIMEOUT): 127 | time.sleep_ms(50) 128 | self.cmd(58, 0, 0, 4) 129 | self.cmd(55, 0, 0) 130 | if self.cmd(41, 0x40000000, 0) == 0: 131 | self.cmd(58, 0, 0, 4) 132 | self.cdv = 1 133 | # print("[SDCard] v2 card") 134 | return 135 | raise OSError("timeout waiting for v2 card") 136 | 137 | def cmd(self, cmd, arg, crc, final=0, release=True, skip1=False): 138 | self.cs(0) 139 | 140 | # create and send the command 141 | buf = self.cmdbuf 142 | buf[0] = 0x40 | cmd 143 | buf[1] = arg >> 24 144 | buf[2] = arg >> 16 145 | buf[3] = arg >> 8 146 | buf[4] = arg 147 | buf[5] = crc 148 | self.spi.write(buf) 149 | 150 | if skip1: 151 | self.spi.readinto(self.tokenbuf, 0xFF) 152 | 153 | # wait for the response (response[7] == 0) 154 | for i in range(_CMD_TIMEOUT): 155 | self.spi.readinto(self.tokenbuf, 0xFF) 156 | response = self.tokenbuf[0] 157 | if not (response & 0x80): 158 | # this could be a big-endian integer that we are getting here 159 | for j in range(final): 160 | self.spi.write(b"\xff") 161 | if release: 162 | self.cs(1) 163 | self.spi.write(b"\xff") 164 | return response 165 | 166 | # timeout 167 | self.cs(1) 168 | self.spi.write(b"\xff") 169 | return -1 170 | 171 | def readinto(self, buf): 172 | self.cs(0) 173 | 174 | # read until start byte (0xff) 175 | for i in range(_CMD_TIMEOUT): 176 | self.spi.readinto(self.tokenbuf, 0xFF) 177 | if self.tokenbuf[0] == _TOKEN_DATA: 178 | break 179 | else: 180 | self.cs(1) 181 | raise OSError("timeout waiting for response") 182 | 183 | # read data 184 | mv = self.dummybuf_memoryview 185 | if len(buf) != len(mv): 186 | mv = mv[: len(buf)] 187 | self.spi.write_readinto(mv, buf) 188 | 189 | # read checksum 190 | self.spi.write(b"\xff") 191 | self.spi.write(b"\xff") 192 | 193 | self.cs(1) 194 | self.spi.write(b"\xff") 195 | 196 | def write(self, token, buf): 197 | self.cs(0) 198 | 199 | # send: start of block, data, checksum 200 | self.spi.read(1, token) 201 | self.spi.write(buf) 202 | self.spi.write(b"\xff") 203 | self.spi.write(b"\xff") 204 | 205 | # check the response 206 | if (self.spi.read(1, 0xFF)[0] & 0x1F) != 0x05: 207 | self.cs(1) 208 | self.spi.write(b"\xff") 209 | return 210 | 211 | # wait for write to finish 212 | while self.spi.read(1, 0xFF)[0] == 0: 213 | pass 214 | 215 | self.cs(1) 216 | self.spi.write(b"\xff") 217 | 218 | def write_token(self, token): 219 | self.cs(0) 220 | self.spi.read(1, token) 221 | self.spi.write(b"\xff") 222 | # wait for write to finish 223 | while self.spi.read(1, 0xFF)[0] == 0x00: 224 | pass 225 | 226 | self.cs(1) 227 | self.spi.write(b"\xff") 228 | 229 | def readblocks(self, block_num, buf): 230 | self.spi.write(b'\xff') # PGH 231 | nblocks = len(buf) // 512 232 | assert nblocks and not len(buf) % 512, "Buffer length is invalid" 233 | if nblocks == 1: 234 | # CMD17: set read address for single block 235 | if self.cmd(17, block_num * self.cdv, 0, release=False) != 0: 236 | # release the card 237 | self.cs(1) 238 | raise OSError(5) # EIO 239 | # receive the data and release card 240 | self.readinto(buf) 241 | else: 242 | # CMD18: set read address for multiple blocks 243 | if self.cmd(18, block_num * self.cdv, 0, release=False) != 0: 244 | # release the card 245 | self.cs(1) 246 | raise OSError(5) # EIO 247 | offset = 0 248 | mv = memoryview(buf) 249 | while nblocks: 250 | # receive the data and release card 251 | self.readinto(mv[offset : offset + 512]) 252 | offset += 512 253 | nblocks -= 1 254 | if self.cmd(12, 0, 0xFF, skip1=True): 255 | raise OSError(5) # EIO 256 | 257 | def writeblocks(self, block_num, buf): 258 | # clock card at least 100 cycles with cs high 259 | self.spi.write(b'\xff') # PGH 260 | nblocks, err = divmod(len(buf), 512) 261 | assert nblocks and not err, "Buffer length is invalid" 262 | if nblocks == 1: 263 | # CMD24: set write address for single block 264 | if self.cmd(24, block_num * self.cdv, 0) != 0: 265 | raise OSError(5) # EIO 266 | 267 | # send the data 268 | self.write(_TOKEN_DATA, buf) 269 | else: 270 | # CMD25: set write address for first block 271 | if self.cmd(25, block_num * self.cdv, 0) != 0: 272 | raise OSError(5) # EIO 273 | # send the data 274 | offset = 0 275 | mv = memoryview(buf) 276 | while nblocks: 277 | self.write(_TOKEN_CMD25, mv[offset : offset + 512]) 278 | offset += 512 279 | nblocks -= 1 280 | self.write_token(_TOKEN_STOP_TRAN) 281 | 282 | def ioctl(self, op, arg): 283 | if op == 4: # get number of blocks 284 | return self.sectors 285 | -------------------------------------------------------------------------------- /modules/vga1_8x16.py: -------------------------------------------------------------------------------- 1 | """converted from vga_8x16.bin """ 2 | WIDTH = 8 3 | HEIGHT = 16 4 | FIRST = 0x20 5 | LAST = 0x7f 6 | _FONT =\ 7 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 8 | b'\x00\x00\x18\x3c\x3c\x3c\x18\x18\x18\x00\x18\x18\x00\x00\x00\x00'\ 9 | b'\x00\x66\x66\x66\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 10 | b'\x00\x00\x00\x6c\x6c\xfe\x6c\x6c\x6c\xfe\x6c\x6c\x00\x00\x00\x00'\ 11 | b'\x18\x18\x7c\xc6\xc2\xc0\x7c\x06\x06\x86\xc6\x7c\x18\x18\x00\x00'\ 12 | b'\x00\x00\x00\x00\xc2\xc6\x0c\x18\x30\x60\xc6\x86\x00\x00\x00\x00'\ 13 | b'\x00\x00\x38\x6c\x6c\x38\x76\xdc\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 14 | b'\x00\x30\x30\x30\x60\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 15 | b'\x00\x00\x0c\x18\x30\x30\x30\x30\x30\x30\x18\x0c\x00\x00\x00\x00'\ 16 | b'\x00\x00\x30\x18\x0c\x0c\x0c\x0c\x0c\x0c\x18\x30\x00\x00\x00\x00'\ 17 | b'\x00\x00\x00\x00\x00\x66\x3c\xff\x3c\x66\x00\x00\x00\x00\x00\x00'\ 18 | b'\x00\x00\x00\x00\x00\x18\x18\x7e\x18\x18\x00\x00\x00\x00\x00\x00'\ 19 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x18\x18\x30\x00\x00\x00'\ 20 | b'\x00\x00\x00\x00\x00\x00\x00\xfe\x00\x00\x00\x00\x00\x00\x00\x00'\ 21 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x18\x00\x00\x00\x00'\ 22 | b'\x00\x00\x00\x00\x02\x06\x0c\x18\x30\x60\xc0\x80\x00\x00\x00\x00'\ 23 | b'\x00\x00\x38\x6c\xc6\xc6\xd6\xd6\xc6\xc6\x6c\x38\x00\x00\x00\x00'\ 24 | b'\x00\x00\x18\x38\x78\x18\x18\x18\x18\x18\x18\x7e\x00\x00\x00\x00'\ 25 | b'\x00\x00\x7c\xc6\x06\x0c\x18\x30\x60\xc0\xc6\xfe\x00\x00\x00\x00'\ 26 | b'\x00\x00\x7c\xc6\x06\x06\x3c\x06\x06\x06\xc6\x7c\x00\x00\x00\x00'\ 27 | b'\x00\x00\x0c\x1c\x3c\x6c\xcc\xfe\x0c\x0c\x0c\x1e\x00\x00\x00\x00'\ 28 | b'\x00\x00\xfe\xc0\xc0\xc0\xfc\x06\x06\x06\xc6\x7c\x00\x00\x00\x00'\ 29 | b'\x00\x00\x38\x60\xc0\xc0\xfc\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 30 | b'\x00\x00\xfe\xc6\x06\x06\x0c\x18\x30\x30\x30\x30\x00\x00\x00\x00'\ 31 | b'\x00\x00\x7c\xc6\xc6\xc6\x7c\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 32 | b'\x00\x00\x7c\xc6\xc6\xc6\x7e\x06\x06\x06\x0c\x78\x00\x00\x00\x00'\ 33 | b'\x00\x00\x00\x00\x18\x18\x00\x00\x00\x18\x18\x00\x00\x00\x00\x00'\ 34 | b'\x00\x00\x00\x00\x18\x18\x00\x00\x00\x18\x18\x30\x00\x00\x00\x00'\ 35 | b'\x00\x00\x00\x06\x0c\x18\x30\x60\x30\x18\x0c\x06\x00\x00\x00\x00'\ 36 | b'\x00\x00\x00\x00\x00\x7e\x00\x00\x7e\x00\x00\x00\x00\x00\x00\x00'\ 37 | b'\x00\x00\x00\x60\x30\x18\x0c\x06\x0c\x18\x30\x60\x00\x00\x00\x00'\ 38 | b'\x00\x00\x7c\xc6\xc6\x0c\x18\x18\x18\x00\x18\x18\x00\x00\x00\x00'\ 39 | b'\x00\x00\x00\x7c\xc6\xc6\xde\xde\xde\xdc\xc0\x7c\x00\x00\x00\x00'\ 40 | b'\x00\x00\x10\x38\x6c\xc6\xc6\xfe\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 41 | b'\x00\x00\xfc\x66\x66\x66\x7c\x66\x66\x66\x66\xfc\x00\x00\x00\x00'\ 42 | b'\x00\x00\x3c\x66\xc2\xc0\xc0\xc0\xc0\xc2\x66\x3c\x00\x00\x00\x00'\ 43 | b'\x00\x00\xf8\x6c\x66\x66\x66\x66\x66\x66\x6c\xf8\x00\x00\x00\x00'\ 44 | b'\x00\x00\xfe\x66\x62\x68\x78\x68\x60\x62\x66\xfe\x00\x00\x00\x00'\ 45 | b'\x00\x00\xfe\x66\x62\x68\x78\x68\x60\x60\x60\xf0\x00\x00\x00\x00'\ 46 | b'\x00\x00\x3c\x66\xc2\xc0\xc0\xde\xc6\xc6\x66\x3a\x00\x00\x00\x00'\ 47 | b'\x00\x00\xc6\xc6\xc6\xc6\xfe\xc6\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 48 | b'\x00\x00\x3c\x18\x18\x18\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 49 | b'\x00\x00\x1e\x0c\x0c\x0c\x0c\x0c\xcc\xcc\xcc\x78\x00\x00\x00\x00'\ 50 | b'\x00\x00\xe6\x66\x66\x6c\x78\x78\x6c\x66\x66\xe6\x00\x00\x00\x00'\ 51 | b'\x00\x00\xf0\x60\x60\x60\x60\x60\x60\x62\x66\xfe\x00\x00\x00\x00'\ 52 | b'\x00\x00\xc6\xee\xfe\xfe\xd6\xc6\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 53 | b'\x00\x00\xc6\xe6\xf6\xfe\xde\xce\xc6\xc6\xc6\xc6\x00\x00\x00\x00'\ 54 | b'\x00\x00\x7c\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 55 | b'\x00\x00\xfc\x66\x66\x66\x7c\x60\x60\x60\x60\xf0\x00\x00\x00\x00'\ 56 | b'\x00\x00\x7c\xc6\xc6\xc6\xc6\xc6\xc6\xd6\xde\x7c\x0c\x0e\x00\x00'\ 57 | b'\x00\x00\xfc\x66\x66\x66\x7c\x6c\x66\x66\x66\xe6\x00\x00\x00\x00'\ 58 | b'\x00\x00\x7c\xc6\xc6\x60\x38\x0c\x06\xc6\xc6\x7c\x00\x00\x00\x00'\ 59 | b'\x00\x00\x7e\x7e\x5a\x18\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 60 | b'\x00\x00\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 61 | b'\x00\x00\xc6\xc6\xc6\xc6\xc6\xc6\xc6\x6c\x38\x10\x00\x00\x00\x00'\ 62 | b'\x00\x00\xc6\xc6\xc6\xc6\xd6\xd6\xd6\xfe\xee\x6c\x00\x00\x00\x00'\ 63 | b'\x00\x00\xc6\xc6\x6c\x7c\x38\x38\x7c\x6c\xc6\xc6\x00\x00\x00\x00'\ 64 | b'\x00\x00\x66\x66\x66\x66\x3c\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 65 | b'\x00\x00\xfe\xc6\x86\x0c\x18\x30\x60\xc2\xc6\xfe\x00\x00\x00\x00'\ 66 | b'\x00\x00\x3c\x30\x30\x30\x30\x30\x30\x30\x30\x3c\x00\x00\x00\x00'\ 67 | b'\x00\x00\x00\x80\xc0\xe0\x70\x38\x1c\x0e\x06\x02\x00\x00\x00\x00'\ 68 | b'\x00\x00\x3c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x3c\x00\x00\x00\x00'\ 69 | b'\x10\x38\x6c\xc6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 70 | b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x00'\ 71 | b'\x00\x30\x18\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 72 | b'\x00\x00\x00\x00\x00\x78\x0c\x7c\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 73 | b'\x00\x00\xe0\x60\x60\x78\x6c\x66\x66\x66\x66\x7c\x00\x00\x00\x00'\ 74 | b'\x00\x00\x00\x00\x00\x7c\xc6\xc0\xc0\xc0\xc6\x7c\x00\x00\x00\x00'\ 75 | b'\x00\x00\x1c\x0c\x0c\x3c\x6c\xcc\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 76 | b'\x00\x00\x00\x00\x00\x7c\xc6\xfe\xc0\xc0\xc6\x7c\x00\x00\x00\x00'\ 77 | b'\x00\x00\x1c\x36\x32\x30\x78\x30\x30\x30\x30\x78\x00\x00\x00\x00'\ 78 | b'\x00\x00\x00\x00\x00\x76\xcc\xcc\xcc\xcc\xcc\x7c\x0c\xcc\x78\x00'\ 79 | b'\x00\x00\xe0\x60\x60\x6c\x76\x66\x66\x66\x66\xe6\x00\x00\x00\x00'\ 80 | b'\x00\x00\x18\x18\x00\x38\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 81 | b'\x00\x00\x06\x06\x00\x0e\x06\x06\x06\x06\x06\x06\x66\x66\x3c\x00'\ 82 | b'\x00\x00\xe0\x60\x60\x66\x6c\x78\x78\x6c\x66\xe6\x00\x00\x00\x00'\ 83 | b'\x00\x00\x38\x18\x18\x18\x18\x18\x18\x18\x18\x3c\x00\x00\x00\x00'\ 84 | b'\x00\x00\x00\x00\x00\xec\xfe\xd6\xd6\xd6\xd6\xc6\x00\x00\x00\x00'\ 85 | b'\x00\x00\x00\x00\x00\xdc\x66\x66\x66\x66\x66\x66\x00\x00\x00\x00'\ 86 | b'\x00\x00\x00\x00\x00\x7c\xc6\xc6\xc6\xc6\xc6\x7c\x00\x00\x00\x00'\ 87 | b'\x00\x00\x00\x00\x00\xdc\x66\x66\x66\x66\x66\x7c\x60\x60\xf0\x00'\ 88 | b'\x00\x00\x00\x00\x00\x76\xcc\xcc\xcc\xcc\xcc\x7c\x0c\x0c\x1e\x00'\ 89 | b'\x00\x00\x00\x00\x00\xdc\x76\x66\x60\x60\x60\xf0\x00\x00\x00\x00'\ 90 | b'\x00\x00\x00\x00\x00\x7c\xc6\x60\x38\x0c\xc6\x7c\x00\x00\x00\x00'\ 91 | b'\x00\x00\x10\x30\x30\xfc\x30\x30\x30\x30\x36\x1c\x00\x00\x00\x00'\ 92 | b'\x00\x00\x00\x00\x00\xcc\xcc\xcc\xcc\xcc\xcc\x76\x00\x00\x00\x00'\ 93 | b'\x00\x00\x00\x00\x00\xc6\xc6\xc6\xc6\xc6\x6c\x38\x00\x00\x00\x00'\ 94 | b'\x00\x00\x00\x00\x00\xc6\xc6\xd6\xd6\xd6\xfe\x6c\x00\x00\x00\x00'\ 95 | b'\x00\x00\x00\x00\x00\xc6\x6c\x38\x38\x38\x6c\xc6\x00\x00\x00\x00'\ 96 | b'\x00\x00\x00\x00\x00\xc6\xc6\xc6\xc6\xc6\xc6\x7e\x06\x0c\xf8\x00'\ 97 | b'\x00\x00\x00\x00\x00\xfe\xcc\x18\x30\x60\xc6\xfe\x00\x00\x00\x00'\ 98 | b'\x00\x00\x0e\x18\x18\x18\x70\x18\x18\x18\x18\x0e\x00\x00\x00\x00'\ 99 | b'\x00\x00\x18\x18\x18\x18\x18\x18\x18\x18\x18\x18\x00\x00\x00\x00'\ 100 | b'\x00\x00\x70\x18\x18\x18\x0e\x18\x18\x18\x18\x70\x00\x00\x00\x00'\ 101 | b'\x00\x76\xdc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\ 102 | b'\x00\x00\x00\x00\x10\x38\x6c\xc6\xc6\xc6\xfe\x00\x00\x00\x00\x00'\ 103 | 104 | FONT = memoryview(_FONT) 105 | -------------------------------------------------------------------------------- /modules/vga1_8x8.py: -------------------------------------------------------------------------------- 1 | """converted from vga_8x8.bin """ 2 | WIDTH = 8 3 | HEIGHT = 8 4 | FIRST = 0x20 5 | LAST = 0x7f 6 | _FONT =\ 7 | b'\x00\x00\x00\x00\x00\x00\x00\x00'\ 8 | b'\x18\x3c\x3c\x18\x18\x00\x18\x00'\ 9 | b'\x66\x66\x24\x00\x00\x00\x00\x00'\ 10 | b'\x6c\x6c\xfe\x6c\xfe\x6c\x6c\x00'\ 11 | b'\x18\x3e\x60\x3c\x06\x7c\x18\x00'\ 12 | b'\x00\xc6\xcc\x18\x30\x66\xc6\x00'\ 13 | b'\x38\x6c\x38\x76\xdc\xcc\x76\x00'\ 14 | b'\x18\x18\x30\x00\x00\x00\x00\x00'\ 15 | b'\x0c\x18\x30\x30\x30\x18\x0c\x00'\ 16 | b'\x30\x18\x0c\x0c\x0c\x18\x30\x00'\ 17 | b'\x00\x66\x3c\xff\x3c\x66\x00\x00'\ 18 | b'\x00\x18\x18\x7e\x18\x18\x00\x00'\ 19 | b'\x00\x00\x00\x00\x00\x18\x18\x30'\ 20 | b'\x00\x00\x00\x7e\x00\x00\x00\x00'\ 21 | b'\x00\x00\x00\x00\x00\x18\x18\x00'\ 22 | b'\x06\x0c\x18\x30\x60\xc0\x80\x00'\ 23 | b'\x38\x6c\xc6\xd6\xc6\x6c\x38\x00'\ 24 | b'\x18\x38\x18\x18\x18\x18\x7e\x00'\ 25 | b'\x7c\xc6\x06\x1c\x30\x66\xfe\x00'\ 26 | b'\x7c\xc6\x06\x3c\x06\xc6\x7c\x00'\ 27 | b'\x1c\x3c\x6c\xcc\xfe\x0c\x1e\x00'\ 28 | b'\xfe\xc0\xc0\xfc\x06\xc6\x7c\x00'\ 29 | b'\x38\x60\xc0\xfc\xc6\xc6\x7c\x00'\ 30 | b'\xfe\xc6\x0c\x18\x30\x30\x30\x00'\ 31 | b'\x7c\xc6\xc6\x7c\xc6\xc6\x7c\x00'\ 32 | b'\x7c\xc6\xc6\x7e\x06\x0c\x78\x00'\ 33 | b'\x00\x18\x18\x00\x00\x18\x18\x00'\ 34 | b'\x00\x18\x18\x00\x00\x18\x18\x30'\ 35 | b'\x06\x0c\x18\x30\x18\x0c\x06\x00'\ 36 | b'\x00\x00\x7e\x00\x00\x7e\x00\x00'\ 37 | b'\x60\x30\x18\x0c\x18\x30\x60\x00'\ 38 | b'\x7c\xc6\x0c\x18\x18\x00\x18\x00'\ 39 | b'\x7c\xc6\xde\xde\xde\xc0\x78\x00'\ 40 | b'\x38\x6c\xc6\xfe\xc6\xc6\xc6\x00'\ 41 | b'\xfc\x66\x66\x7c\x66\x66\xfc\x00'\ 42 | b'\x3c\x66\xc0\xc0\xc0\x66\x3c\x00'\ 43 | b'\xf8\x6c\x66\x66\x66\x6c\xf8\x00'\ 44 | b'\xfe\x62\x68\x78\x68\x62\xfe\x00'\ 45 | b'\xfe\x62\x68\x78\x68\x60\xf0\x00'\ 46 | b'\x3c\x66\xc0\xc0\xce\x66\x3a\x00'\ 47 | b'\xc6\xc6\xc6\xfe\xc6\xc6\xc6\x00'\ 48 | b'\x3c\x18\x18\x18\x18\x18\x3c\x00'\ 49 | b'\x1e\x0c\x0c\x0c\xcc\xcc\x78\x00'\ 50 | b'\xe6\x66\x6c\x78\x6c\x66\xe6\x00'\ 51 | b'\xf0\x60\x60\x60\x62\x66\xfe\x00'\ 52 | b'\xc6\xee\xfe\xfe\xd6\xc6\xc6\x00'\ 53 | b'\xc6\xe6\xf6\xde\xce\xc6\xc6\x00'\ 54 | b'\x7c\xc6\xc6\xc6\xc6\xc6\x7c\x00'\ 55 | b'\xfc\x66\x66\x7c\x60\x60\xf0\x00'\ 56 | b'\x7c\xc6\xc6\xc6\xc6\xce\x7c\x0e'\ 57 | b'\xfc\x66\x66\x7c\x6c\x66\xe6\x00'\ 58 | b'\x3c\x66\x30\x18\x0c\x66\x3c\x00'\ 59 | b'\x7e\x7e\x5a\x18\x18\x18\x3c\x00'\ 60 | b'\xc6\xc6\xc6\xc6\xc6\xc6\x7c\x00'\ 61 | b'\xc6\xc6\xc6\xc6\xc6\x6c\x38\x00'\ 62 | b'\xc6\xc6\xc6\xd6\xd6\xfe\x6c\x00'\ 63 | b'\xc6\xc6\x6c\x38\x6c\xc6\xc6\x00'\ 64 | b'\x66\x66\x66\x3c\x18\x18\x3c\x00'\ 65 | b'\xfe\xc6\x8c\x18\x32\x66\xfe\x00'\ 66 | b'\x3c\x30\x30\x30\x30\x30\x3c\x00'\ 67 | b'\xc0\x60\x30\x18\x0c\x06\x02\x00'\ 68 | b'\x3c\x0c\x0c\x0c\x0c\x0c\x3c\x00'\ 69 | b'\x10\x38\x6c\xc6\x00\x00\x00\x00'\ 70 | b'\x00\x00\x00\x00\x00\x00\x00\xff'\ 71 | b'\x30\x18\x0c\x00\x00\x00\x00\x00'\ 72 | b'\x00\x00\x78\x0c\x7c\xcc\x76\x00'\ 73 | b'\xe0\x60\x7c\x66\x66\x66\xdc\x00'\ 74 | b'\x00\x00\x7c\xc6\xc0\xc6\x7c\x00'\ 75 | b'\x1c\x0c\x7c\xcc\xcc\xcc\x76\x00'\ 76 | b'\x00\x00\x7c\xc6\xfe\xc0\x7c\x00'\ 77 | b'\x3c\x66\x60\xf8\x60\x60\xf0\x00'\ 78 | b'\x00\x00\x76\xcc\xcc\x7c\x0c\xf8'\ 79 | b'\xe0\x60\x6c\x76\x66\x66\xe6\x00'\ 80 | b'\x18\x00\x38\x18\x18\x18\x3c\x00'\ 81 | b'\x06\x00\x06\x06\x06\x66\x66\x3c'\ 82 | b'\xe0\x60\x66\x6c\x78\x6c\xe6\x00'\ 83 | b'\x38\x18\x18\x18\x18\x18\x3c\x00'\ 84 | b'\x00\x00\xec\xfe\xd6\xd6\xd6\x00'\ 85 | b'\x00\x00\xdc\x66\x66\x66\x66\x00'\ 86 | b'\x00\x00\x7c\xc6\xc6\xc6\x7c\x00'\ 87 | b'\x00\x00\xdc\x66\x66\x7c\x60\xf0'\ 88 | b'\x00\x00\x76\xcc\xcc\x7c\x0c\x1e'\ 89 | b'\x00\x00\xdc\x76\x60\x60\xf0\x00'\ 90 | b'\x00\x00\x7e\xc0\x7c\x06\xfc\x00'\ 91 | b'\x30\x30\xfc\x30\x30\x36\x1c\x00'\ 92 | b'\x00\x00\xcc\xcc\xcc\xcc\x76\x00'\ 93 | b'\x00\x00\xc6\xc6\xc6\x6c\x38\x00'\ 94 | b'\x00\x00\xc6\xd6\xd6\xfe\x6c\x00'\ 95 | b'\x00\x00\xc6\x6c\x38\x6c\xc6\x00'\ 96 | b'\x00\x00\xc6\xc6\xc6\x7e\x06\xfc'\ 97 | b'\x00\x00\x7e\x4c\x18\x32\x7e\x00'\ 98 | b'\x0e\x18\x18\x70\x18\x18\x0e\x00'\ 99 | b'\x18\x18\x18\x18\x18\x18\x18\x00'\ 100 | b'\x70\x18\x18\x0e\x18\x18\x70\x00'\ 101 | b'\x76\xdc\x00\x00\x00\x00\x00\x00'\ 102 | b'\x00\x10\x38\x6c\xc6\xc6\xfe\x00'\ 103 | 104 | FONT = memoryview(_FONT) 105 | -------------------------------------------------------------------------------- /st7789/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | # BasedOnStyle: LLVM 3 | AccessModifierOffset: -2 4 | ConstructorInitializerIndentWidth: 4 5 | AlignEscapedNewlinesLeft: false 6 | AlignTrailingComments: true 7 | AllowAllParametersOfDeclarationOnNextLine: true 8 | AllowShortIfStatementsOnASingleLine: false 9 | AllowShortLoopsOnASingleLine: false 10 | AlwaysBreakTemplateDeclarations: false 11 | AlwaysBreakBeforeMultilineStrings: false 12 | BreakBeforeBinaryOperators: false 13 | BreakBeforeTernaryOperators: true 14 | BreakConstructorInitializersBeforeComma: false 15 | BinPackParameters: true 16 | ColumnLimit: 0 17 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 18 | DerivePointerBinding: false 19 | ExperimentalAutoDetectBinPacking: false 20 | IndentCaseLabels: true 21 | MaxEmptyLinesToKeep: 1 22 | NamespaceIndentation: None 23 | ObjCSpaceBeforeProtocolList: true 24 | PenaltyBreakBeforeFirstCallParameter: 19 25 | PenaltyBreakComment: 60 26 | PenaltyBreakString: 1000 27 | PenaltyBreakFirstLessLess: 120 28 | PenaltyExcessCharacter: 1000000 29 | PenaltyReturnTypeOnItsOwnLine: 60 30 | PointerBindsToType: false 31 | SpacesBeforeTrailingComments: 1 32 | Cpp11BracedListStyle: true 33 | Standard: Cpp03 34 | IndentWidth: 4 35 | TabWidth: 4 36 | UseTab: Always 37 | BreakBeforeBraces: WebKit 38 | IndentFunctionDeclarationAfterType: false 39 | SpacesInParentheses: false 40 | SpacesInAngles: false 41 | SpaceInEmptyParentheses: false 42 | SpacesInCStyleCastParentheses: false 43 | SpaceAfterControlStatementKeyword: true 44 | SpaceBeforeAssignmentOperators: true 45 | ContinuationIndentWidth: 4 46 | IndentWrappedFunctionNames: true 47 | KeepEmptyLinesAtTheStartOfBlocks: false 48 | SortIncludes: false 49 | SpaceAfterCStyleCast: true 50 | SpacesInSquareBrackets: false 51 | AlignConsecutiveAssignments: true 52 | AlignConsecutiveDeclarations: true 53 | ... 54 | 55 | -------------------------------------------------------------------------------- /st7789/jpg/tjpgd565.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------------/ 2 | / TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2020 3 | /----------------------------------------------------------------------------*/ 4 | #ifndef DEF_TJPGDEC 5 | #define DEF_TJPGDEC 6 | /*---------------------------------------------------------------------------*/ 7 | /* System Configurations */ 8 | 9 | #define JD_SZBUF 512 /* Size of stream input buffer */ 10 | #define JD_FORMAT 1 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ 11 | #define JD_USE_SCALE 1 /* Use descaling feature for output */ 12 | #define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ 13 | 14 | /*---------------------------------------------------------------------------*/ 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | #include "stdint.h" 21 | 22 | /* Error code */ 23 | typedef enum { 24 | JDR_OK = 0, /* 0: Succeeded */ 25 | JDR_INTR, /* 1: Interrupted by output function */ 26 | JDR_INP, /* 2: Device error or wrong termination of input stream */ 27 | JDR_MEM1, /* 3: Insufficient memory pool for the image */ 28 | JDR_MEM2, /* 4: Insufficient stream input buffer */ 29 | JDR_PAR, /* 5: Parameter error */ 30 | JDR_FMT1, /* 6: Data format error (may be damaged data) */ 31 | JDR_FMT2, /* 7: Right format but not supported */ 32 | JDR_FMT3 /* 8: Not supported JPEG standard */ 33 | } JRESULT; 34 | 35 | 36 | 37 | /* Rectangular structure */ 38 | typedef struct { 39 | uint16_t left, right, top, bottom; 40 | } JRECT; 41 | 42 | 43 | 44 | /* Decompressor object structure */ 45 | typedef struct JDEC JDEC; 46 | struct JDEC { 47 | unsigned int dctr; /* Number of bytes available in the input buffer */ 48 | uint8_t* dptr; /* Current data read ptr */ 49 | uint8_t* inbuf; /* Bit stream input buffer */ 50 | uint8_t dmsk; /* Current bit in the current read byte */ 51 | uint8_t scale; /* Output scaling ratio */ 52 | uint8_t msx, msy; /* MCU size in unit of block (width, height) */ 53 | uint8_t qtid[3]; /* Quantization table ID of each component */ 54 | int16_t dcv[3]; /* Previous DC element of each component */ 55 | uint16_t nrst; /* Restart inverval */ 56 | uint16_t width, height; /* Size of the input image (pixel) */ 57 | uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ 58 | uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ 59 | uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ 60 | int32_t* qttbl[4]; /* Dequantizer tables [id] */ 61 | void* workbuf; /* Working buffer for IDCT and RGB output */ 62 | uint8_t* mcubuf; /* Working buffer for the MCU */ 63 | void* pool; /* Pointer to available memory pool */ 64 | unsigned int sz_pool; /* Size of momory pool (bytes available) */ 65 | unsigned int (*infunc)(JDEC*, uint8_t*, unsigned int); /* Pointer to jpeg stream input function */ 66 | void* device; /* Pointer to I/O device identifiler for the session */ 67 | uint16_t x_offs; /* x offset for slow method */ 68 | uint16_t y_offs; /* y offset for slow method */ 69 | }; 70 | 71 | 72 | /* TJpgDec API functions */ 73 | JRESULT jd_prepare (JDEC* jd, unsigned int (*infunc)(JDEC*,uint8_t*,unsigned int), void* pool, unsigned int sz_pool, void* dev); 74 | JRESULT jd_decomp (JDEC* jd, int (*outfunc)(JDEC*,void*,JRECT*), uint8_t scale); 75 | 76 | 77 | #ifdef __cplusplus 78 | } 79 | #endif 80 | 81 | #endif /* _TJPGDEC */ 82 | -------------------------------------------------------------------------------- /st7789/micropython.cmake: -------------------------------------------------------------------------------- 1 | 2 | # Create an INTERFACE library for our C module. 3 | add_library(usermod_st7789 INTERFACE) 4 | 5 | # Add our source files to the lib 6 | target_sources(usermod_st7789 INTERFACE 7 | ${CMAKE_CURRENT_LIST_DIR}/st7789.c 8 | ${CMAKE_CURRENT_LIST_DIR}/mpfile.c 9 | ${CMAKE_CURRENT_LIST_DIR}/jpg/tjpgd565.c 10 | ${CMAKE_CURRENT_LIST_DIR}/png/pngle.c 11 | ${CMAKE_CURRENT_LIST_DIR}/png/miniz.c 12 | ) 13 | 14 | # Add the current directory as an include directory. 15 | target_include_directories(usermod_st7789 INTERFACE 16 | ${CMAKE_CURRENT_LIST_DIR} 17 | 18 | ) 19 | 20 | # Link our INTERFACE library to the usermod target. 21 | target_link_libraries(usermod INTERFACE usermod_st7789) 22 | -------------------------------------------------------------------------------- /st7789/mpfile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Micro Python project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2016 Dave Hylands 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #include "py/builtin.h" 28 | #include "py/misc.h" 29 | #include "py/runtime.h" 30 | #include "mpfile.h" 31 | 32 | #include "extmod/vfs.h" 33 | 34 | #include 35 | #include 36 | 37 | 38 | static const mp_obj_type_t mp_file_type; 39 | static mp_obj_t mp___del__(mp_obj_t self); 40 | 41 | mp_file_t *mp_file_from_file_obj(mp_obj_t file_obj) { 42 | mp_file_t *file = m_new_obj(mp_file_t); 43 | memset(file, 0, sizeof(*file)); 44 | file->base.type = &mp_file_type; 45 | file->file_obj = file_obj; 46 | file->readinto_fn = mp_load_attr(file->file_obj, MP_QSTR_readinto); 47 | file->seek_fn = mp_load_attr(file->file_obj, MP_QSTR_seek); 48 | file->tell_fn = mp_load_attr(file->file_obj, MP_QSTR_tell); 49 | 50 | return file; 51 | } 52 | 53 | mp_file_t *mp_open(const char *filename, const char *mode) { 54 | mp_obj_t filename_obj = mp_obj_new_str(filename, strlen(filename)); 55 | mp_obj_t mode_obj = mp_obj_new_str(mode, strlen(mode)); 56 | mp_obj_t args[2] = { filename_obj, mode_obj }; 57 | return mp_file_from_file_obj(mp_vfs_open(2, args, (mp_map_t *)&mp_const_empty_map)); 58 | } 59 | 60 | mp_int_t mp_readinto(mp_file_t *file, void *buf, size_t num_bytes) { 61 | mp_int_t nread; 62 | 63 | mp_obj_t bytearray = mp_obj_new_bytearray_by_ref(num_bytes, buf); 64 | mp_obj_t bytes_read = mp_call_function_1(file->readinto_fn, bytearray); 65 | if (bytes_read == mp_const_none) { 66 | return 0; 67 | } 68 | nread = mp_obj_get_int(bytes_read); 69 | return nread; 70 | } 71 | 72 | off_t mp_seek(mp_file_t *file, off_t offset, int whence) { 73 | return mp_obj_get_int(mp_call_function_2(file->seek_fn, 74 | MP_OBJ_NEW_SMALL_INT(offset), 75 | MP_OBJ_NEW_SMALL_INT(whence))); 76 | } 77 | 78 | off_t mp_tell(mp_file_t *file) { 79 | return mp_obj_get_int(mp_call_function_0(file->tell_fn)); 80 | } 81 | 82 | void mp_close(mp_file_t *file) { 83 | 84 | mp_obj_t close_fn = mp_load_attr(file->file_obj, MP_QSTR_close); 85 | file->file_obj = mp_const_none; 86 | file->readinto_fn = mp_const_none; 87 | file->seek_fn = mp_const_none; 88 | file->tell_fn = mp_const_none; 89 | mp_call_function_0(close_fn); 90 | } 91 | 92 | static void mp_file_print(const mp_print_t *print, mp_obj_t self, mp_print_kind_t kind) { 93 | (void)kind; 94 | mp_printf(print, "", self); 95 | } 96 | 97 | static mp_obj_t mp___del__(mp_obj_t self) { 98 | mp_close(MP_OBJ_TO_PTR(self)); 99 | return mp_const_none; 100 | } 101 | static MP_DEFINE_CONST_FUN_OBJ_1(mp___del___obj, mp___del__); 102 | 103 | static const mp_rom_map_elem_t mp_file_locals_dict_table[] = { 104 | { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp___del___obj) }, 105 | }; 106 | static MP_DEFINE_CONST_DICT(mp_file_locals_dict, mp_file_locals_dict_table); 107 | 108 | 109 | #if MICROPY_OBJ_TYPE_REPR == MICROPY_OBJ_TYPE_REPR_SLOT_INDEX 110 | 111 | static MP_DEFINE_CONST_OBJ_TYPE( 112 | mp_file_type, 113 | MP_QSTR_mp_file, 114 | MP_TYPE_FLAG_NONE, 115 | print, mp_file_print, 116 | locals_dict, &mp_file_locals_dict 117 | ); 118 | 119 | #else 120 | 121 | static const mp_obj_type_t mp_file_type = { 122 | .base = { &mp_type_type }, 123 | .name = MP_QSTR_mp_file, 124 | .print = mp_file_print, 125 | .locals_dict = (mp_obj_dict_t *)&mp_file_locals_dict, 126 | }; 127 | 128 | #endif -------------------------------------------------------------------------------- /st7789/mpfile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the Micro Python project, http://micropython.org/ 3 | * 4 | * The MIT License (MIT) 5 | * 6 | * Copyright (c) 2016 Dave Hylands 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | 27 | #ifndef __MICROPY_INCLUDED_PY_MPFILE_H__ 28 | #define __MICROPY_INCLUDED_PY_MPFILE_H__ 29 | 30 | #include "py/obj.h" 31 | #include // for off_t 32 | 33 | // A C API for performing I/O on files or file-like objects. 34 | 35 | typedef struct { 36 | mp_obj_base_t base; 37 | mp_obj_t file_obj; 38 | mp_obj_t readinto_fn; 39 | mp_obj_t seek_fn; 40 | mp_obj_t tell_fn; 41 | } mp_file_t; 42 | 43 | #define MP_SEEK_SET 0 44 | #define MP_SEEK_CUR 1 45 | #define MP_SEEK_END 2 46 | 47 | mp_file_t *mp_file_from_file_obj(mp_obj_t file_obj); 48 | mp_file_t *mp_open(const char *filename, const char *mode); 49 | mp_int_t mp_readinto(mp_file_t *file, void *buf, size_t num_bytes); 50 | off_t mp_seek(mp_file_t *file, off_t offset, int whence); 51 | off_t mp_tell(mp_file_t *file); 52 | void mp_close(mp_file_t *file); 53 | 54 | 55 | #endif // __MICROPY_INCLUDED_PY_MPFILE_H__ 56 | -------------------------------------------------------------------------------- /st7789/png/miniz.h: -------------------------------------------------------------------------------- 1 | #define MINIZ_HEADER_FILE_ONLY 2 | #include "miniz.c" 3 | -------------------------------------------------------------------------------- /st7789/png/pngle.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 kikuchan 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | #ifndef __PNGLE_H__ 26 | #define __PNGLE_H__ 27 | 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | // Main Pngle object 35 | typedef struct _pngle_t pngle_t; 36 | 37 | // Callback signatures 38 | typedef void (*pngle_init_callback_t)(pngle_t *pngle, uint32_t w, uint32_t h); 39 | typedef void (*pngle_draw_callback_t)(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4]); 40 | typedef void (*pngle_done_callback_t)(pngle_t *pngle); 41 | 42 | // ---------------- 43 | // Basic interfaces 44 | // ---------------- 45 | pngle_t *pngle_new(); 46 | void pngle_destroy(pngle_t *pngle); 47 | void pngle_reset(pngle_t *pngle); // clear its internal state (not applied to pngle_set_* functions) 48 | const char *pngle_error(pngle_t *pngle); 49 | int pngle_feed(pngle_t *pngle, const void *buf, size_t len); // returns -1: On error, 0: Need more data, n: n bytes eaten 50 | 51 | uint32_t pngle_get_width(pngle_t *pngle); 52 | uint32_t pngle_get_height(pngle_t *pngle); 53 | 54 | void pngle_set_init_callback(pngle_t *png, pngle_init_callback_t callback); 55 | void pngle_set_draw_callback(pngle_t *png, pngle_draw_callback_t callback); 56 | void pngle_set_done_callback(pngle_t *png, pngle_done_callback_t callback); 57 | 58 | void pngle_set_display_gamma(pngle_t *pngle, double display_gamma); // enables gamma correction by specifying display gamma, typically 2.2. No effect when gAMA chunk is missing 59 | 60 | void pngle_set_user_data(pngle_t *pngle, void *user_data); 61 | void *pngle_get_user_data(pngle_t *pngle); 62 | 63 | 64 | // ---------------- 65 | // Debug interfaces 66 | // ---------------- 67 | 68 | typedef struct _pngle_ihdr_t { 69 | uint32_t width; 70 | uint32_t height; 71 | uint8_t depth; 72 | uint8_t color_type; 73 | uint8_t compression; 74 | uint8_t filter; 75 | uint8_t interlace; 76 | } pngle_ihdr_t; 77 | 78 | // Get IHDR information 79 | pngle_ihdr_t *pngle_get_ihdr(pngle_t *pngle); 80 | 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | 86 | #endif /* __PNGLE_H__ */ 87 | -------------------------------------------------------------------------------- /st7789/st7789.h: -------------------------------------------------------------------------------- 1 | #ifndef __ST7789_H__ 2 | #define __ST7789_H__ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // color modes 9 | #define COLOR_MODE_65K 0x50 10 | #define COLOR_MODE_262K 0x60 11 | #define COLOR_MODE_12BIT 0x03 12 | #define COLOR_MODE_16BIT 0x05 13 | #define COLOR_MODE_18BIT 0x06 14 | #define COLOR_MODE_16M 0x07 15 | 16 | // commands 17 | #define ST7789_NOP 0x00 18 | #define ST7789_SWRESET 0x01 19 | #define ST7789_RDDID 0x04 20 | #define ST7789_RDDST 0x09 21 | 22 | #define ST7789_SLPIN 0x10 23 | #define ST7789_SLPOUT 0x11 24 | #define ST7789_PTLON 0x12 25 | #define ST7789_NORON 0x13 26 | 27 | #define ST7789_INVOFF 0x20 28 | #define ST7789_INVON 0x21 29 | #define ST7789_DISPOFF 0x28 30 | #define ST7789_DISPON 0x29 31 | #define ST7789_CASET 0x2A 32 | #define ST7789_RASET 0x2B 33 | #define ST7789_RAMWR 0x2C 34 | #define ST7789_RAMRD 0x2E 35 | 36 | #define ST7789_PTLAR 0x30 37 | #define ST7789_VSCRDEF 0x33 38 | #define ST7789_COLMOD 0x3A 39 | #define ST7789_MADCTL 0x36 40 | #define ST7789_VSCSAD 0x37 41 | 42 | #define ST7789_MADCTL_MY 0x80 // Page Address Order 43 | #define ST7789_MADCTL_MX 0x40 // Column Address Order 44 | #define ST7789_MADCTL_MV 0x20 // Page/Column Order 45 | #define ST7789_MADCTL_ML 0x10 // Line Address Order 46 | #define ST7789_MADCTL_MH 0x04 // Display Data Latch Order 47 | #define ST7789_MADCTL_RGB 0x00 48 | #define ST7789_MADCTL_BGR 0x08 49 | 50 | #define ST7789_RDID1 0xDA 51 | #define ST7789_RDID2 0xDB 52 | #define ST7789_RDID3 0xDC 53 | #define ST7789_RDID4 0xDD 54 | 55 | // Color definitions 56 | #define BLACK 0x0000 57 | #define BLUE 0x001F 58 | #define RED 0xF800 59 | #define GREEN 0x07E0 60 | #define CYAN 0x07FF 61 | #define MAGENTA 0xF81F 62 | #define YELLOW 0xFFE0 63 | #define WHITE 0xFFFF 64 | 65 | #define OPTIONS_WRAP_V 0x01 66 | #define OPTIONS_WRAP_H 0x02 67 | #define OPTIONS_WRAP 0x03 68 | 69 | typedef struct _Point { 70 | mp_float_t x; 71 | mp_float_t y; 72 | } Point; 73 | 74 | typedef struct _Polygon { 75 | int length; 76 | Point *points; 77 | } Polygon; 78 | 79 | typedef struct _st7789_rotation_t { 80 | uint8_t madctl; 81 | uint16_t width; 82 | uint16_t height; 83 | uint16_t colstart; 84 | uint16_t rowstart; 85 | } st7789_rotation_t; 86 | 87 | // this is the actual C-structure for our new object 88 | typedef struct _st7789_ST7789_obj_t { 89 | mp_obj_base_t base; 90 | 91 | mp_hal_pin_obj_t wr; // write pin 92 | mp_hal_pin_obj_t rd; // read pin 93 | 94 | mp_file_t *fp; // file object 95 | uint16_t *pixel_buffer; // resident buffer if buffer_size given 96 | 97 | // m_malloc'd pointers 98 | void *work; // work buffer for jpg & png decoding 99 | uint8_t *scanline_ringbuf; // png scanline_ringbuf 100 | uint8_t *palette; // png palette 101 | uint8_t *trans_palette; // png trans_palette 102 | uint8_t *gamma_table; // png gamma_table 103 | 104 | size_t buffer_size; // resident buffer size, 0=dynamic 105 | uint16_t display_width; // physical width 106 | uint16_t width; // logical width (after rotation) 107 | uint16_t display_height; // physical width 108 | uint16_t height; // logical height (after rotation) 109 | uint8_t colstart; 110 | uint8_t rowstart; 111 | uint8_t rotation; 112 | st7789_rotation_t *rotations; // list of rotation tuples [(madctl, colstart, rowstart)] 113 | uint8_t rotations_len; // number of rotations 114 | uint8_t color_order; 115 | bool inversion; 116 | uint8_t madctl; 117 | uint8_t options; // options bit array 118 | mp_hal_pin_obj_t reset; 119 | mp_hal_pin_obj_t dc; 120 | mp_hal_pin_obj_t cs; 121 | mp_hal_pin_obj_t backlight; 122 | 123 | uint8_t bounding; 124 | uint16_t min_x; 125 | uint16_t min_y; 126 | uint16_t max_x; 127 | uint16_t max_y; 128 | 129 | } st7789_ST7789_obj_t; 130 | 131 | mp_obj_t st7789_ST7789_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args); 132 | 133 | extern void draw_pixel(st7789_ST7789_obj_t *self, int16_t x, int16_t y, uint16_t color); 134 | extern void fast_hline(st7789_ST7789_obj_t *self, int16_t x, int16_t y, int16_t w, uint16_t color); 135 | 136 | #ifdef __cplusplus 137 | } 138 | #endif /* __cplusplus */ 139 | 140 | #endif /* __ST7789_H__ */ 141 | -------------------------------------------------------------------------------- /utils/font_from_romfont.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Convert fonts from the font-bin directory of spacerace's 4 | https://github.com/spacerace/romfont repo. 5 | 6 | Reads all romfont bin files from the specified -input-directory (-i) and writes 7 | python font files to the specified -output-directory (-o). Optionally limiting 8 | characters included to -first-char (-f) thru -last-char (-l). 9 | 10 | Example: 11 | 12 | font_from_romfont -i font-bin -o pyfont -f 32 -l 127 13 | 14 | requires argparse 15 | """ 16 | import os 17 | import re 18 | import argparse 19 | 20 | def convert_font(file_in, file_out, width, height, first=0x0, last=0xff): 21 | chunk_size = height 22 | with open(file_in, "rb") as bin_file: 23 | bin_file.seek(first * height) 24 | current = first 25 | with open(file_out, 'wt') as font_file: 26 | print(f'"""converted from {file_in} """', file=font_file) 27 | print(f'WIDTH = {width}', file=font_file) 28 | print(f'HEIGHT = {height}', file=font_file) 29 | print(f'FIRST = 0x{first:02x}', file=font_file) 30 | print(f'LAST = 0x{last:02x}', file=font_file) 31 | print('_FONT =\\\n', sep='', end='', file=font_file) 32 | for chunk in iter(lambda: bin_file.read(chunk_size), b''): 33 | print('b\'', sep='', end='', file=font_file) 34 | for data in chunk: 35 | print(f'\\x{data:02x}', end='', file=font_file) 36 | print('\'\\', file=font_file) 37 | current += 1 38 | if current > last: 39 | break 40 | 41 | print('', file=font_file) 42 | print('FONT = memoryview(_FONT)', file=font_file) 43 | 44 | def auto_int(x): 45 | return int(x, 0) 46 | 47 | def main(): 48 | parser = argparse.ArgumentParser( 49 | description='Convert Romfont.bin font files in input to python in font_directory.') 50 | parser.add_argument('input', help='file or directory containing binary font file(s).') 51 | parser.add_argument('output', help='file or directory to contain python font file(s).') 52 | parser.add_argument('-f', '--first-char', type=auto_int, default=0x20) 53 | parser.add_argument('-l', '--last-char', type=auto_int, default=0x7f) 54 | args = parser.parse_args() 55 | 56 | file_re = re.compile(r'^(.*)(\d+)x(\d+)\.bin$') 57 | 58 | is_dir = os.path.isdir(args.input) 59 | bin_files = os.listdir(args.input) if is_dir else [args.input] 60 | for bin_file_name in bin_files: 61 | match = file_re.match(bin_file_name) 62 | if match: 63 | font_width = int(match.group(2)) 64 | font_height = int(match.group(3)) 65 | 66 | if is_dir: 67 | bin_file_name = args.input+'/'+bin_file_name 68 | 69 | if is_dir: 70 | font_file_name = ( 71 | args.font_directory + '/' + 72 | match.group(1).rstrip('_').lower()+ 73 | f'_{font_width}x{font_height}.py') 74 | else: 75 | font_file_name = args.output 76 | 77 | print("converting", bin_file_name, 'to', font_file_name) 78 | 79 | convert_font( 80 | bin_file_name, 81 | font_file_name, 82 | font_width, 83 | font_height, 84 | args.first_char, 85 | args.last_char) 86 | 87 | main() 88 | -------------------------------------------------------------------------------- /utils/howto-convert-to-jpg: -------------------------------------------------------------------------------- 1 | # 2 | # You can convert images to compatible jpg's by using ImageMagick's convert 3 | # utility by specifying the output type as TrueColor. ImageMagick downloads 4 | # are available from https://imagemagick.org/ for Linux, OSX, Windows and 5 | # other operating systems. 6 | # 7 | # The wi-alien.svg icon is from https://github.com/erikflowers/weather-icons 8 | # licensed under SIL OFL 1.1 9 | # 10 | 11 | convert wi-alien.svg -type TrueColor alien.jpg 12 | -------------------------------------------------------------------------------- /utils/imgtobitmap.py: -------------------------------------------------------------------------------- 1 | #!python3 2 | ''' 3 | Convert image file to python module for use with blit_bitmap. 4 | 5 | Usage imgtobitmap image_file bits_per_pixel >image.py 6 | ''' 7 | 8 | import sys 9 | from PIL import Image 10 | import argparse 11 | 12 | 13 | def main(): 14 | 15 | parser = argparse.ArgumentParser( 16 | prog='imgtobitmap', 17 | description='Convert image file to python module for use with bitmap method.') 18 | 19 | parser.add_argument( 20 | 'image_file', 21 | help='Name of file containing image to convert') 22 | 23 | parser.add_argument( 24 | 'bits_per_pixel', 25 | type=int, 26 | choices=range(1, 9), 27 | default=1, 28 | metavar='bits_per_pixel', 29 | help='The number of bits to use per pixel (1..8)') 30 | 31 | args = parser.parse_args() 32 | bits = args.bits_per_pixel 33 | colors_requested = 1 << bits 34 | img = Image.open(args.image_file) 35 | img = img.convert("P", palette=Image.Palette.ADAPTIVE, colors=colors_requested) 36 | palette = img.getpalette() # Make copy of palette colors 37 | palette_colors = len(palette) // 3 38 | bits_required = palette_colors.bit_length() 39 | if (bits_required < bits): 40 | print(f'\nNOTE: Quantization reduced colors to {palette_colors} from the {colors_requested} ' 41 | f'requested, reconverting using {bits_required} bit per pixel could save memory.\n''', file=sys.stderr) 42 | 43 | # For all the colors in the palette 44 | colors = [] 45 | 46 | for color in range(palette_colors): 47 | 48 | # get rgb values and convert to 565 49 | color565 = ( 50 | ((palette[color*3] & 0xF8) << 8) 51 | | ((palette[color*3+1] & 0xFC) << 3) 52 | | ((palette[color*3+2] & 0xF8) >> 3)) 53 | 54 | # swap bytes in 565 55 | color = ((color565 & 0xff) << 8) + ((color565 & 0xff00) >> 8) 56 | 57 | # append byte swapped 565 color to colors 58 | colors.append(f'{color:04x}') 59 | 60 | image_bitstring = '' 61 | max_colors = len() 62 | 63 | # Run through the image and create a string with the ascii binary 64 | # representation of the color of each pixel. 65 | for y in range(img.height): 66 | for x in range(img.width): 67 | pixel = img.getpixel((x, y)) 68 | color = pixel 69 | bstring = ''.join( 70 | '1' if (color & (1 << bit - 1)) else '0' 71 | for bit in range(bits, 0, -1) 72 | ) 73 | 74 | image_bitstring += bstring 75 | 76 | bitmap_bits = len(image_bitstring) 77 | 78 | # Create python source with image parameters 79 | print(f'HEIGHT = {img.height}') 80 | print(f'WIDTH = {img.width}') 81 | print(f'COLORS = {max_colors}') 82 | print(f'BITS = {bitmap_bits}') 83 | print(f'BPP = {bits}') 84 | print('PALETTE = [', sep='', end='') 85 | 86 | for color, rgb in enumerate(colors): 87 | if color: 88 | print(',', sep='', end='') 89 | print(f'0x{rgb}', sep='', end='') 90 | print("]") 91 | 92 | # Run though image bit string 8 bits at a time 93 | # and create python array source for memoryview 94 | 95 | print("_bitmap =\\", sep='') 96 | print("b'", sep='', end='') 97 | 98 | for i in range(0, bitmap_bits, 8): 99 | 100 | if i and i % (16*8) == 0: 101 | print("'\\\nb'", end='', sep='') 102 | 103 | value = image_bitstring[i:i+8] 104 | color = int(value, 2) 105 | print(f'\\x{color:02x}', sep='', end='') 106 | 107 | print("'\nBITMAP = memoryview(_bitmap)") 108 | 109 | 110 | main() 111 | -------------------------------------------------------------------------------- /utils/monofont2bitmap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | monofont2bitmap.py 5 | Convert characters from monospace truetype fonts to a python bitmap 6 | for use with the bitmap method in the st7789 and ili9342 drivers. 7 | 8 | positional arguments: 9 | 10 | font_file Name of font file to convert. 11 | font_size Size of font to create bitmaps from. 12 | bits_per_pixel The number of bits (1..8) to use per pixel. 13 | 14 | optional arguments: 15 | 16 | -h, --help show this help message and exit 17 | -f FOREGROUND, --foreground FOREGROUND 18 | Foreground color of characters. 19 | -b BACKGROUND, --background BACKGROUND 20 | Background color of characters. 21 | 22 | character selection: 23 | Characters from the font to include in the bitmap. 24 | 25 | -c CHARACTERS, --characters CHARACTERS 26 | integer or hex character values and/or ranges to 27 | include. 28 | 29 | For example: "65, 66, 67" or "32-127" or 30 | "0x30-0x39, 0x41-0x5a" 31 | 32 | -s STRING, --string STRING 33 | String of characters to include For example: 34 | "1234567890-." 35 | ''' 36 | 37 | import sys 38 | import shlex 39 | from PIL import Image, ImageFont, ImageDraw 40 | import argparse 41 | 42 | image_bitstring = '' 43 | 44 | 45 | def to_int(str): 46 | return int(str, base=16) if str.startswith("0x") else int(str) 47 | 48 | 49 | def get_characters(str): 50 | return ''.join(chr(b) for a in [ 51 | (lambda sub: range(sub[0], sub[-1] + 1)) 52 | (list(map(to_int, ele.split('-')))) 53 | for ele in str.split(',')] for b in a) 54 | 55 | def process_char(img, bits): 56 | global image_bitstring 57 | 58 | # Run through the image and create a string with the ascii binary 59 | # representation of the color of each pixel. 60 | 61 | for y in range(img.height): 62 | for x in range(img.width): 63 | pixel = img.getpixel((x, y)) 64 | color = pixel 65 | bit_string = ''.join( 66 | '1' if (color & (1 << bit - 1)) else '0' 67 | for bit in range(bits, 0, -1) 68 | ) 69 | 70 | image_bitstring += bit_string 71 | 72 | 73 | def main(): 74 | parser = argparse.ArgumentParser( 75 | prog='font2bitmap', 76 | description=(''' 77 | Convert characters from monospace truetype fonts to a 78 | python bitmap for use with the bitmap method in the 79 | st7789 and ili9342 drivers.''')) 80 | 81 | parser.add_argument( 82 | 'font_file', 83 | help='Name of font file to convert.') 84 | 85 | parser.add_argument( 86 | 'font_size', 87 | type=int, 88 | default=8, 89 | help='Size of font to create bitmaps from.') 90 | 91 | parser.add_argument( 92 | 'bits_per_pixel', 93 | type=int, 94 | choices=range(1, 9), 95 | default=1, 96 | metavar='bits_per_pixel', 97 | help='The number of bits (1..8) to use per pixel.') 98 | 99 | parser.add_argument( 100 | '-f', '--foreground', 101 | default='white', 102 | help='Foreground color of characters.') 103 | 104 | parser.add_argument( 105 | '-b', '--background', 106 | default='black', 107 | help='Background color of characters.') 108 | 109 | group = parser.add_argument_group( 110 | 'character selection', 111 | 'Characters from the font to include in the bitmap.') 112 | 113 | excl = group.add_mutually_exclusive_group() 114 | excl.add_argument( 115 | '-c', '--characters', 116 | help='''integer or hex character values and/or ranges to include. 117 | For example: "65, 66, 67" or "32-127" or "0x30-0x39, 0x41-0x5a"''') 118 | 119 | excl.add_argument( 120 | '-s', '--string', 121 | help='''String of characters to include 122 | For example: "1234567890-."''') 123 | 124 | args = parser.parse_args() 125 | bpp = args.bits_per_pixel 126 | font_file = args.font_file 127 | font_size = args.font_size 128 | 129 | if args.string is None: 130 | characters = get_characters(args.characters) 131 | else: 132 | characters = args.string 133 | 134 | forground = args.foreground 135 | background = args.background 136 | 137 | # load font and get size of characters string in pixels 138 | font = ImageFont.truetype(font_file, font_size) 139 | size = font.getsize(characters) 140 | 141 | # create image large enough to all characters 142 | im = Image.new('RGB', size, color=background) 143 | 144 | # draw all specified characters in the image 145 | draw = ImageDraw.Draw(im) 146 | draw.text((0, 0), characters, font=font, color=forground) 147 | 148 | # convert image to a palletized image with the requested color depth 149 | bpp_im = im.convert(mode='P', palette=Image.ADAPTIVE, colors=1 << bpp) 150 | palette = bpp_im.getpalette() 151 | 152 | # convert all characters into a ascii bit string 153 | ofs = 0 154 | for char in characters: 155 | char_size = font.getsize(char) 156 | crop = (ofs, 0, ofs + char_size[0], size[1]) 157 | char_im = bpp_im.crop(crop) 158 | process_char(char_im, bpp) 159 | ofs += char_size[0] 160 | 161 | bitmap_bits = len(image_bitstring) 162 | char_map = characters.replace('\\', '\\\\').replace('"', '\\"') 163 | cmdline = " ".join(map(shlex.quote, sys.argv)) 164 | 165 | # Create python source 166 | print('# coding=UTF8') 167 | print(f'# Converted from {font_file} using:') 168 | print(f'# {cmdline}') 169 | print() 170 | print(f'HEIGHT = {char_im.height}') 171 | print(f'WIDTH = {char_im.width}') 172 | print(f'COLORS = {1 << bpp}') 173 | print(f'BITMAPS = {len(characters)}') 174 | print(f'MAP = "{char_map}"') 175 | print(f'BPP = {bpp}') 176 | print('PALETTE = [', sep='', end='') 177 | 178 | # For all the colors in the palette 179 | colors = [] 180 | for color in range(1 << bpp): 181 | 182 | # get rgb values and convert to 565 183 | color565 = ( 184 | ((palette[color*3] & 0xF8) << 8) | 185 | ((palette[color*3+1] & 0xFC) << 3) | 186 | ((palette[color*3+2] & 0xF8) >> 3)) 187 | 188 | # swap bytes in 565 189 | color = ((color565 & 0xff) << 8) + ((color565 & 0xff00) >> 8) 190 | 191 | # append byte swapped 565 color to colors 192 | colors.append(f'{color:04x}') 193 | 194 | # write color palette colors 195 | for color, rgb in enumerate(colors): 196 | if color: 197 | print(', ', sep='', end='') 198 | 199 | print(f'0x{rgb}', sep='', end='') 200 | print(']') 201 | 202 | # Run though image bit string 8 bits at a time 203 | # and create python array source for memoryview 204 | 205 | print('_BITMAP =\\', sep='') 206 | print(' b\'', sep='', end='') 207 | 208 | for i in range(0, bitmap_bits, 8): 209 | if i and i % (16 * 8) == 0: 210 | print("'\\\n b'", end='', sep='') 211 | 212 | value = image_bitstring[i:i+8] 213 | color = int(value, 2) 214 | print(f'\\x{color:02x}', sep='', end='') 215 | 216 | print("'\\\n b'", end='', sep='') 217 | print("'\n\nBITMAP = memoryview(_BITMAP)") 218 | 219 | 220 | main() 221 | -------------------------------------------------------------------------------- /utils/png_from_font.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Imports all the python font files from the specified -input-directory (-i) and 5 | creates png samples of each font in the specified -output-directory (-o). 6 | 7 | Example: 8 | png_from_font.py font_directory png_directory 9 | 10 | Requires argparse, importlib and pypng 11 | """ 12 | 13 | import os 14 | import importlib 15 | import png 16 | import argparse 17 | 18 | def create_png(font_file_name, png_file_name): 19 | 20 | module_spec = importlib.util.spec_from_file_location('font', font_file_name) 21 | font = importlib.util.module_from_spec(module_spec) 22 | module_spec.loader.exec_module(font) 23 | char_count = font.LAST - font.FIRST 24 | column_count = 16 25 | row_count = (char_count // column_count) 26 | 27 | with open(png_file_name, 'wb') as png_file: 28 | image = png.Writer((16+2) * font.WIDTH, (row_count+3) * font.HEIGHT, bitdepth=1) 29 | image_data = [[0 for j in range((16+2) * font.WIDTH)] for i in range((row_count+3)* font.HEIGHT)] 30 | for chart_row in range(row_count+2): 31 | for chart_col in range(16): 32 | chart_idx = chart_row * 16 + chart_col 33 | for char_line in range(font.HEIGHT): 34 | for char_byte in range(font.WIDTH//8): 35 | ch_idx = chart_idx * font.HEIGHT * font.WIDTH//8 + char_byte + char_line * font.WIDTH//8 36 | print(chart_idx, char_count) 37 | if (chart_idx <= char_count): 38 | data = font.FONT[ch_idx] 39 | else: 40 | data = 0 41 | 42 | for bit in range(8): 43 | png_row = (chart_row+1)*font.HEIGHT+char_line 44 | png_col = (chart_col+1)*font.WIDTH+char_byte*8+bit 45 | if data & 1 << 7-bit: 46 | image_data[png_row][png_col] = 1 47 | else: 48 | image_data[png_row][png_col] = 0 49 | 50 | print("Creating", png_file_name) 51 | image.write(png_file, image_data) 52 | 53 | def main(): 54 | parser = argparse.ArgumentParser( 55 | description='Convert 8bit font-bin.bin font files in bin_directory to python in font_directory.') 56 | parser.add_argument( 57 | 'font_directory', help='directory containing python font files. (input)') 58 | parser.add_argument( 59 | 'png_directory', help='directory to contain binary font files. (output)') 60 | args = parser.parse_args() 61 | 62 | for file_name in os.listdir(args.font_directory): 63 | if file_name.endswith('.py'): 64 | font_file_name = args.font_directory+'/'+file_name 65 | png_file_name = args.png_directory+'/'+os.path.splitext(file_name)[0]+'.png' 66 | create_png(font_file_name, png_file_name) 67 | 68 | main() 69 | -------------------------------------------------------------------------------- /utils/requirements.txt: -------------------------------------------------------------------------------- 1 | Pillow==9.0.1 2 | pypng==0.0.20 3 | freetype-py==2.2.0 -------------------------------------------------------------------------------- /utils/sprites2bitmap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | ''' 4 | Convert a sprite sheet image to python a module for use with indexed bitmap method. 5 | Sprite sheet width and height should be a multiple of sprite width and height. There 6 | should be no extra pixels between sprites. All sprites will share the same palette. 7 | 8 | Usage: 9 | sprites2bitmap image_file spite_width sprite_height bits_per_pixel >sprites.py 10 | 11 | MicroPython: 12 | import sprites 13 | ... tft config and init code ... 14 | tft.bitmap(sprites, x, y, index) 15 | 16 | ''' 17 | 18 | from os import setpriority 19 | from PIL import Image 20 | import argparse 21 | 22 | def main(): 23 | 24 | parser = argparse.ArgumentParser( 25 | prog='imgtobitmap', 26 | description='Convert image file to python module for use with bitmap method.') 27 | 28 | parser.add_argument( 29 | 'image_file', 30 | help='Name of file containing image to convert') 31 | 32 | parser.add_argument( 33 | 'sprite_width', 34 | type=int, 35 | help='width of sprites in pixels') 36 | 37 | parser.add_argument( 38 | 'sprite_height', 39 | type=int, 40 | help='height of sprites in pixels') 41 | 42 | parser.add_argument( 43 | 'bits_per_pixel', 44 | type=int, 45 | choices=range(1, 9), 46 | default=1, 47 | metavar='bits_per_pixel', 48 | help='The number of bits to use per pixel (1..8)') 49 | 50 | args = parser.parse_args() 51 | 52 | bits = args.bits_per_pixel 53 | img = Image.open(args.image_file) 54 | img = img.convert("P", palette=Image.ADAPTIVE, colors=2**bits) 55 | palette = img.getpalette() # Make copy of palette colors 56 | 57 | # For all the colors in the palette 58 | colors = [] 59 | for color in range(1 << bits): 60 | 61 | # get rgb values and convert to 565 62 | color565 = ( 63 | ((palette[color*3] & 0xF8) << 8) | 64 | ((palette[color*3+1] & 0xFC) << 3) | 65 | ((palette[color*3+2] & 0xF8) >> 3)) 66 | 67 | # swap bytes in 565 68 | color = ((color565 & 0xff) << 8) + ((color565 & 0xff00) >> 8) 69 | 70 | # append byte swapped 565 color to colors 71 | colors.append(f'{color:04x}') 72 | 73 | image_bitstring = '' 74 | max_colors = 1 << bits 75 | bitmaps = 0 76 | # Run through the image and create a string with the ascii binary 77 | # representation of the color of each pixel. 78 | for y in range(0, img.height, args.sprite_height): 79 | for x in range(0, img.width, args.sprite_width): 80 | bitmaps += 1 81 | for yy in range(y, y + args.sprite_height): 82 | for xx in range(x, x + args.sprite_width): 83 | pixel = img.getpixel((xx, yy)) 84 | color = pixel 85 | image_bitstring += ''.join( 86 | '1' if (color & (1 << bit - 1)) else '0' for bit in range(bits, 0, -1)) 87 | 88 | bitmap_bits = len(image_bitstring) 89 | 90 | # Create python source with image parameters 91 | print(f'BITMAPS = {bitmaps}') 92 | print(f'HEIGHT = {args.sprite_height}') 93 | print(f'WIDTH = {args.sprite_width}') 94 | print(f'COLORS = {max_colors}') 95 | print(f'BITS = {bitmap_bits}') 96 | print(f'BPP = {bits}') 97 | print('PALETTE = [', sep='', end='') 98 | 99 | for color, rgb in enumerate(colors): 100 | if color: 101 | print(',', sep='', end='') 102 | print(f'0x{rgb}', sep='', end='') 103 | print("]") 104 | 105 | # Run though image bit string 8 bits at a time 106 | # and create python array source for memoryview 107 | 108 | print("_bitmap =\\", sep='') 109 | print("b'", sep='', end='') 110 | 111 | for i in range(0, bitmap_bits, 8): 112 | 113 | if i and i % (16*8) == 0: 114 | print("'\\\nb'", end='', sep='') 115 | 116 | value = image_bitstring[i:i+8] 117 | color = int(value, 2) 118 | print(f'\\x{color:02x}', sep='', end='') 119 | 120 | print("'\nBITMAP = memoryview(_bitmap)") 121 | 122 | 123 | main() 124 | -------------------------------------------------------------------------------- /utils/wi-alien.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 16 | 17 | --------------------------------------------------------------------------------