├── .gitignore
├── LICENSE
├── README.md
├── docs
├── gauge-generator
│ ├── Oswald-Bold.ttf
│ ├── Oswald-Light.ttf
│ ├── gauge1.py
│ └── pointer1.py
├── gc9a01_demo1.jpg
├── gc9a01_demo2.jpg
├── gc9a01_pico_wiring1.jpg
└── gc9a01_qtpy_wiring1.jpg
├── examples
├── eyeballs
│ ├── gc9a01_lizard_eye.py
│ ├── gc9a01_multi_eyeball.py
│ ├── imgs
│ │ ├── Lizard_Iris_White.bmp
│ │ ├── Lizard_Sclera.bmp
│ │ ├── eye0_ball2.bmp
│ │ └── eye0_iris0.bmp
│ ├── qteye.py
│ └── qteye_person_sensor.py
├── gc9a01_gauge_knob.py
├── gc9a01_hellocircles.py
├── gc9a01_hellocircles_pico_compact.py
├── gc9a01_helloworld.py
├── gc9a01_picture_locket.py
├── imgs
│ ├── dial-background.bmp
│ ├── dial-percenti.bmp
│ ├── lars240.bmp
│ ├── max1.bmp
│ ├── max2.bmp
│ ├── pointer-red-basic-30x140-c15x105.bmp
│ └── pointer-red-basic-30x140.bmp
└── pico_boot.py
└── old_driver
└── todbot_gc9a01.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Tod E. Kurt
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 all
13 | 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 THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CircuitPython GC9A01 demos
2 |
3 | Demos showing how to use [CircuitPython displayio driver](https://github.com/tylercrumpton/CircuitPython_GC9A01) for GC9A01-based round LCDs. This driver is available in the [CircuitPython Community Bundle](https://github.com/adafruit/CircuitPython_Community_Bundle), or you can install it by hand by copying the `gc9a01.py` file to your `CIRCUITPY/lib` directory, or use `circup install gc9a01`.
4 |
5 |
6 |
7 |
8 | ## Usage
9 |
10 | ```py
11 | import board
12 | import busio
13 | import fourwire
14 | import displayio
15 | import gc9a01
16 | displayio.release_displays()
17 | # Raspberry Pi Pico pinout, one possibility, at "southwest" of board
18 | tft_clk = board.GP10 # must be a SPI CLK
19 | tft_mosi= board.GP11 # must be a SPI TX
20 | tft_rst = board.GP12
21 | tft_dc = board.GP13
22 | tft_cs = board.GP14 # optional, can be "None"
23 | tft_bl = board.GP15 # optional, can be "None"
24 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
25 | display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
26 | display = gc9a01.GC9A01(display_bus, width=240, height=240, backlight_pin=tft_bl)
27 |
28 | # ... normal circuitpython displayio stuff
29 | ```
30 |
31 | ## Installation
32 |
33 | Each of the .py files in "examples" is its own demo. Copy one of these to be your CIRCUITPY's "code.py", like:
34 | ```
35 | cp gc9a01_hellocircles.py /Volumes/CIRCUITPY/code.py
36 | ```
37 |
38 | You'll need to install various libraries. Most notably the `gc9a01` library. You may also
39 | need the `adafruit_display_text` and `adafruit_imageload`, depending on the example.
40 | The easiest way to install these is from a terminal:
41 | ```
42 | circup install gc9a01
43 | circup install adafruit_display_text
44 | circup install adafruit_imageload
45 | ```
46 |
47 |
48 | ## Examples
49 |
50 | Check out the 'examples' directory for complete examples:
51 |
52 | - 'gc9a01_helloworld' -- shows one way of doing polar coordinates
53 | - 'gc9a01_hellocircles' -- similar to above but with floating circles using `vectorio`
54 | - 'gc9a01_picture_locket' -- display a series of pictures, makes a nice locket if used with a QT Py Haxpress
55 | - 'gc9a01_gauge_knob' -- round dial gauge using gauge background & dial bitmaps, showing `bitmaptools.rotozoom`
56 |
57 | The examples attempt to auto-detect the board you're using. The currently detected boards:
58 |
59 | - [QT Py M0 Haxpress](https://circuitpython.org/board/qtpy_m0_haxpress/)
60 | - [QT Py RP2040](https://circuitpython.org/board/adafruit_qtpy_rp2040/)
61 | - [Raspberry Pi Pico](https://circuitpython.org/board/raspberry_pi_pico/)
62 | - [ItsyBitsy M4 Express](https://circuitpython.org/board/itsybitsy_m4_express/)
63 |
64 | ### Eyeballs demos
65 |
66 | Additionally, there are several demos in the "examples/eyeballs" directory that use these round displays to make moving eyes.
67 |
68 | - 'eyeballs/qteye.py' -- single eyeball (or two eyeballs wired in parallel) on a QT PY RP2040 or similar
69 | - 'eyeballs/qtpy_person_sensor.py' -- single eyeball that tracks your face, thanks to a Person Sensor module
70 | - 'eyeballs/gc9a01_lizard_eye.py' -- similar to "qteye" but uses a cool lizard eye (thx @DJDevon3!)
71 | - 'eyeballs/gc9a01_multi_eyeball.py' -- independent multiple eyes usigng a [recompiled CircuitPython](https://todbot.com/blog/2022/05/19/multiple-displays-in-circuitpython-compiling-custom-circuitpython/)
72 |
73 |
74 | ## Wiring
75 |
76 | Wiring is dependent on board you're hooking it up to. The "SCL" and "SDA" lines need to be
77 | hooked up to SPI pins "SCK" and "MOSI/TX". The `gc9a01_helloworld.py` has example wirings for three
78 | different boards. Here is an example for the Pico:
79 |
80 | - VCC - Pico 3.3V(out)
81 | - Gnd - Pico Ground
82 | - SCL - Pico GP10 (SPI1 SCK)
83 | - SDA - Pico GP11 (SPI1 TX)
84 | - RES - Pico GP12
85 | - DC - Pico GP13
86 | - CS - Pico GP14
87 | - BLK - Pico GP15 (can be omitted if you don't need backlight brightness control)
88 |
89 |
90 |
91 |
92 | Here is an example for a QT Py Haxpress:
93 |
94 | - VCC - QT Py 3.3V
95 | - Gnd - QT Py Ground
96 | - SCL - QT Py SCK
97 | - SDA - QT Py MO
98 | - RES - QT Py TX
99 | - DC - QT Py A3
100 | - CS - QT Py A2
101 | - BLK - unconnected
102 |
103 |
104 |
105 |
106 |
107 | ## Building your own dial gauges
108 |
109 | There is a partial Python port of [@bikerglen's gauge-generator](https://github.com/bikerglen/round-lcd-gauges/tree/main/gauge-generator) in [`docs/gauge-generator`](./docs/gauge-generator). These scripts use the wonderful [Wand](https://docs.wand-py.org/en/0.6.6/) Python wrapper for ImageMagick's C API.
110 |
111 |
112 | ## Future Project Ideas:
113 | - bargraph display using vectorio
114 |
115 |
116 |
117 | ### Notes to self:
118 |
119 | - This repo started out as a GC9A01 driver for CircuitPython, but [@tylercrumpton](https://github.com/tylercrumpton/CircuitPython_GC9A01) beat me to the [CircuitPython Community Bundle](https://github.com/adafruit/CircuitPython_Community_Bundle) by a few days. Now it's a repo of demos
120 |
--------------------------------------------------------------------------------
/docs/gauge-generator/Oswald-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/docs/gauge-generator/Oswald-Bold.ttf
--------------------------------------------------------------------------------
/docs/gauge-generator/Oswald-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/docs/gauge-generator/Oswald-Light.ttf
--------------------------------------------------------------------------------
/docs/gauge-generator/gauge1.py:
--------------------------------------------------------------------------------
1 | #
2 | # gauge1.py -- Gauge generator,
3 | # outputs "dial-background.bmp" file for use with CircuitPython
4 | #
5 | # Translated directly from bikerglen's "gauge-generator":
6 | # https://github.com/bikerglen/round-lcd-gauges/tree/main/gauge-generator
7 | #
8 | # To use, install ImageMagic drawing API:
9 | # brew install imagemagick
10 | # pip3 install Wand
11 | # python3 gauage1.py
12 | #
13 |
14 | import math
15 |
16 | from wand.image import Image
17 | from wand.drawing import Drawing
18 | from wand.color import Color
19 |
20 | #
21 | def draw_dial_background(draw):
22 | draw.stroke_color = Color('#d0d0d0')
23 | draw.stroke_width = 1
24 | draw.fill_color = Color('#f0f0f0')
25 | draw.circle( (120,120), (1,120) ) # center point, perimeter point
26 | draw.stroke_color = Color('#e8e8e8')
27 | draw.circle( (120,120), (2,120) )
28 | draw.stroke_color = Color('#d8d8d8')
29 | draw.circle( (120,120), (5,120) )
30 | draw.stroke_color = Color('#d0d0d0')
31 | draw.circle( (120,120), (6,120) )
32 | draw.stroke_color = Color('#c8c8c8')
33 | draw.circle( (120,120), (7,120) )
34 | draw.stroke_color = Color('#c0c0c0')
35 | draw.circle( (120,120), (8,120) )
36 | draw.stroke_color = Color('#e0e0e0')
37 | draw.circle( (120,120), (9,120) )
38 | draw.stroke_color = Color('#e0e0e0')
39 | draw.circle( (120,120), (10,120) )
40 | draw.stroke_color = Color('#e0e0e0')
41 | draw.circle( (120,120), (11,120) )
42 | draw.stroke_color = Color('#c8c8c8')
43 | draw.circle( (120,120), (12,120) )
44 |
45 | #
46 | def draw_dial_ticks(draw, color, stroke_width=1.5, number_of_ticks=360,
47 | start_angle=0, stop_angle=360, start_radius=100, end_radius=120):
48 | for i in range(number_of_ticks):
49 | angle = start_angle + i*(stop_angle-start_angle) /(number_of_ticks-1)
50 | angle_corrected = angle - 90
51 | angle_radians = angle_corrected / 180 * math.pi
52 |
53 | x1 = 120 + math.cos(angle_radians) * start_radius
54 | y1 = 120 + math.sin(angle_radians) * start_radius
55 | x2 = 120 + math.cos(angle_radians) * end_radius
56 | y2 = 120 + math.sin(angle_radians) * end_radius
57 | draw.stroke_color = color
58 | draw.line((x1,y1),(x2,y2))
59 |
60 | #
61 | def label_dial_ticks(draw, image, color, font, radius, number_ticks,
62 | start_angle, stop_angle, start_label, stop_label, label_format):
63 | draw.fill_color = color
64 | draw.stroke_color = color
65 | draw.font = font
66 | draw.font_size = 22
67 | draw.text_alignment = 'center'
68 |
69 | for i in range(number_ticks):
70 | angle = start_angle + i* (stop_angle-start_angle) / (number_ticks-1)
71 | angle_corrected = angle - 90
72 | angle_radians = angle_corrected / 180.0 * math.pi
73 | label_value = start_label + i*(stop_label-start_label) / (number_ticks-1)
74 | label_string = label_format % label_value
75 |
76 | metrics = draw.get_font_metrics(image, label_string)
77 | ascent = metrics.ascender + metrics.descender
78 | roffset = math.sqrt( (math.cos(angle_radians) * metrics.text_width/2) *
79 | (math.cos(angle_radians) * metrics.text_width/2) +
80 | (math.sin(angle_radians) * ascent/2) *
81 | (math.sin(angle_radians) * ascent/2))
82 |
83 |
84 | x1 = int(120 + math.cos(angle_radians) * (radius - roffset))
85 | y1 = int(120 + math.sin(angle_radians) * (radius - roffset) + ascent/2.0)
86 | draw.text( x1, y1, label_string)
87 |
88 | # now create the image and write it out
89 | #
90 | with Image(width=240, height=240, background=Color('#ffffff')) as img:
91 |
92 | with Drawing() as draw:
93 |
94 | draw_dial_background(draw)
95 |
96 | draw_dial_ticks(draw, Color('#606060'), 1.5, 101, -150, 150, 97, 104) # minor
97 | draw_dial_ticks(draw, Color('#606060'), 1.5, 11, -150, 150, 89, 104) # major
98 |
99 | label_dial_ticks(draw, img, Color("#606060"), "Oswald-Light.ttf",
100 | 85, 11, -150,150, 0,100, "%0.0f")
101 |
102 | draw.draw(img)
103 |
104 | img.type = 'palette' # CircuitPython can only do palette BMP3
105 | img.quantize(16) # reduce colors for size
106 | img.save(filename='BMP3:dial-background.bmp')
107 |
108 |
--------------------------------------------------------------------------------
/docs/gauge-generator/pointer1.py:
--------------------------------------------------------------------------------
1 | #
2 | # pointer1.py -- Gauge pointer generator,
3 | # outputs "pointer-red-basic.bmp" file for use with CircuitPython
4 | #
5 | # Translated directly from bikerglen's "gauge-generator":
6 | # https://github.com/bikerglen/round-lcd-gauges/tree/main/gauge-generator
7 | #
8 | # To use, install ImageMagic drawing API:
9 | # brew install imagemagick
10 | # pip3 install Wand
11 | # python3 gauage1.py
12 | #
13 |
14 | import math
15 |
16 | from wand.image import Image
17 | from wand.drawing import Drawing
18 | from wand.color import Color
19 |
20 | def draw_pointer_knub(draw, color, center_x, center_y, radius, opacity):
21 | draw.fill_color = color
22 | draw.stroke_color = Color('#333333')
23 | draw.stroke_opacity = 0.5
24 | draw.stroke_width = 2
25 | draw.fill_opacity = opacity
26 | draw.circle( (center_x, center_y), (center_x - radius, center_y))
27 | # draw.stroke_color=Color('#aaaaaa')
28 | # draw.circle( (center_x, center_y), (center_x - radius + 3, center_y))
29 |
30 | def draw_pointer_needle(draw, color, stroke_width, tip_radius, tail_radius, opacity):
31 | # draw.stroke_opacity = 0.5
32 | # draw.stroke_color = Color('#333333')
33 | # draw.stroke_width = stroke_width+2
34 | # draw.line( (120, 120 + tail_radius+1), (120,120-tip_radius-1))
35 | draw.stroke_width = stroke_width
36 | draw.stroke_color = color
37 | draw.stroke_opacity = opacity
38 | draw.line( (120, 120 + tail_radius), (120,120-tip_radius))
39 | #draw.line( (119.5, 119.5 + tail_radius), (119.5,119.5-tip_radius))
40 |
41 | with Image(width=240, height=240, background=Color('none')) as img:
42 |
43 | with Drawing() as draw:
44 |
45 | # draw_pointer_needle(draw, Color("#F45700"), 2.25, 100, 30, 1);
46 | draw_pointer_needle(draw, Color("#F45700"), 2.25, 102.5, 30.5, 1);
47 | draw_pointer_knub(draw, Color("#F45700"), 120, 120, 10, 1);
48 | # draw_pointer_knub(draw, Color("#F45700"), 119.5, 119.5, 10.1, 1);
49 |
50 | draw.draw(img)
51 |
52 | img.crop( 105, 15, 135, 155)
53 |
54 | fname = 'pointer-red-basic-30x140-c15x105'
55 | img.save(filename=fname+'.png')
56 | img.type = 'palette' # CircuitPython can only do palette BMP3
57 | img.quantize(16) # reduce colors for size
58 | img.save(filename='BMP3:'+fname+'.bmp')
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/docs/gc9a01_demo1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/docs/gc9a01_demo1.jpg
--------------------------------------------------------------------------------
/docs/gc9a01_demo2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/docs/gc9a01_demo2.jpg
--------------------------------------------------------------------------------
/docs/gc9a01_pico_wiring1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/docs/gc9a01_pico_wiring1.jpg
--------------------------------------------------------------------------------
/docs/gc9a01_qtpy_wiring1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/docs/gc9a01_qtpy_wiring1.jpg
--------------------------------------------------------------------------------
/examples/eyeballs/gc9a01_lizard_eye.py:
--------------------------------------------------------------------------------
1 | # qteye.py - a stand-alone GC9A01 round LCD "eye" on a QTPy
2 | # 23 Oct 2022 - @todbot / Tod Kurt
3 | # Gator Eyes by 2022 DJDevon3
4 | # Part of circuitpython-tricks/larger-tricks/eyeballs
5 | # also see: https://todbot.com/blog/2022/05/19/multiple-displays-in-circuitpython-compiling-custom-circuitpython/
6 |
7 | import time, math, random
8 | import board, busio
9 | import displayio
10 | import adafruit_imageload
11 | import gc9a01
12 |
13 | displayio.release_displays()
14 |
15 | dw, dh = 240,240 # display dimensions
16 |
17 | # load our eye and iris bitmaps
18 | eyeball_bitmap, eyeball_pal = adafruit_imageload.load("images/Lizard_Sclera.bmp")
19 | iris_bitmap, iris_pal = adafruit_imageload.load("images/Lizard_Iris_White.bmp")
20 | iris_pal.make_transparent(244)
21 |
22 | # compute or declare some useful info about the eyes
23 | iris_w, iris_h = iris_bitmap.width, iris_bitmap.height # iris is normally 110x110
24 | iris_cx, iris_cy = dw//2 - iris_w//2, dh//2 - iris_h//2
25 | r = 15 # allowable deviation from center for iris
26 |
27 | tft0_clk = board.SCL
28 | tft0_mosi = board.SDA
29 | tft_L0_rst = board.D9
30 | tft_L0_dc = board.D5
31 | tft_L0_cs = board.D6
32 |
33 | spi0 = busio.SPI(clock=tft0_clk, MOSI=tft0_mosi)
34 |
35 | # class to help us track eye info (not needed for this use exactly, but I find it interesting)
36 | class Eye:
37 | def __init__(self, spi, dc, cs, rst, rot=0, eye_speed=0.5, twitch=1):
38 | display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=rst)
39 | display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=rot)
40 | main = displayio.Group()
41 | display.show(main)
42 | self.display = display
43 | self.eyeball = displayio.TileGrid(eyeball_bitmap, pixel_shader=eyeball_pal)
44 | self.iris = displayio.TileGrid(iris_bitmap, pixel_shader=iris_pal, x=iris_cx,y=iris_cy)
45 | main.append(self.eyeball)
46 | main.append(self.iris)
47 | self.x, self.y = iris_cx, iris_cy
48 | self.tx, self.ty = self.x, self.y
49 | self.next_time = time.monotonic()
50 | self.eye_speed = eye_speed
51 | self.twitch = twitch
52 |
53 | def update(self):
54 | self.x = self.x * (1-self.eye_speed) + self.tx * self.eye_speed # "easing"
55 | self.y = self.y * (1-self.eye_speed) + self.ty * self.eye_speed
56 | self.iris.x = int( self.x )
57 | self.iris.y = int( self.y )
58 | if time.monotonic() > self.next_time:
59 | t = random.uniform(0.25,self.twitch)
60 | self.next_time = time.monotonic() + t
61 | self.tx = iris_cx + random.uniform(-r,r)
62 | self.ty = iris_cy + random.uniform(-r,r)
63 | self.display.refresh()
64 |
65 | # a list of all the eyes, in this case, only one
66 | the_eyes = [
67 | Eye( spi0, tft_L0_dc, tft_L0_cs, tft_L0_rst, rot=0),
68 | ]
69 |
70 | while True:
71 | for eye in the_eyes:
72 | eye.update()
73 |
--------------------------------------------------------------------------------
/examples/eyeballs/gc9a01_multi_eyeball.py:
--------------------------------------------------------------------------------
1 | # gc9a01_multi_eyeball_code.py --
2 | # 14 Oct 2022 - @todbot / Tod Kurt
3 | # Part of https://github.com/todbot/CircuitPython_GC9A01_demos
4 | # Requires rebuilt CircuitPython with CIRCUITPY_DISPLAY_LIMIT set to 3
5 | # also see: https://todbot.com/blog/2022/05/19/multiple-displays-in-circuitpython-compiling-custom-circuitpython/
6 |
7 | import time, math, random
8 | import board, busio
9 | import displayio
10 | import adafruit_imageload
11 | import gc9a01
12 |
13 | displayio.release_displays()
14 |
15 | dw, dh = 240,240 # display dimensions
16 |
17 | eyeball_bitmap, eyeball_pal = adafruit_imageload.load("imgs/eye0_ball2.bmp")
18 | iris_bitmap, iris_pal = adafruit_imageload.load("imgs/eye0_iris0.bmp")
19 | iris_pal.make_transparent(0)
20 |
21 | iris_w, iris_h = iris_bitmap.width, iris_bitmap.height # iris is normally 110x110
22 | iris_cx, iris_cy = dw//2 - iris_w//2, dh//2 - iris_h//2
23 |
24 | tft0_clk = board.GP18
25 | tft0_mosi = board.GP19
26 |
27 | tft1_clk = board.GP10
28 | tft1_mosi = board.GP11
29 |
30 | tft_L0_rst = board.GP21
31 | tft_L0_dc = board.GP22
32 | tft_L0_cs = board.GP20
33 |
34 | tft_R0_rst = board.GP26
35 | tft_R0_dc = board.GP27
36 | tft_R0_cs = board.GP28
37 |
38 | tft_L1_rst = board.GP14
39 | tft_L1_dc = board.GP12
40 | tft_L1_cs = board.GP13
41 |
42 | tft_R1_rst = board.GP3
43 | tft_R1_dc = board.GP4
44 | tft_R1_cs = board.GP5
45 |
46 | spi0 = busio.SPI(clock=tft0_clk, MOSI=tft0_mosi)
47 | spi1 = busio.SPI(clock=tft1_clk, MOSI=tft1_mosi)
48 |
49 | def eye_init(spi, dc, cs, rst, rot):
50 | display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=rst)
51 | display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=rot)
52 | main = displayio.Group()
53 | display.show(main)
54 | eyeball = displayio.TileGrid(eyeball_bitmap, pixel_shader=eyeball_pal)
55 | iris = displayio.TileGrid(iris_bitmap, pixel_shader=iris_pal, x = iris_cx, y = iris_cy )
56 | main.append(eyeball)
57 | main.append(iris)
58 | return (display, eyeball, iris)
59 |
60 |
61 | (display_L0, eyeball_L0, iris_L0) = eye_init( spi0, tft_L0_dc, tft_L0_cs, tft_L0_rst, rot=0)
62 | (display_R0, eyeball_R0, iris_R0) = eye_init( spi0, tft_R0_dc, tft_R0_cs, tft_R0_rst, rot=0)
63 | (display_L1, eyeball_L1, iris_L1) = eye_init( spi1, tft_L1_dc, tft_L1_cs, tft_L1_rst, rot=0)
64 | # can't do four yet
65 | #(display_R1, eyeball_R1, iris_R1) = eye_init( spi1, tft_R1_dc, tft_R1_cs, tft_R1_rst, rot=0)
66 |
67 | the_eyes = [
68 | # x,y, tx,ty, next_time
69 | [display_L0, eyeball_L0, iris_L0, iris_cx, iris_cy, 0, 0, 0 ],
70 | [display_R0, eyeball_R0, iris_R0, iris_cx, iris_cy, 0, 0, 0 ],
71 | [display_L1, eyeball_L1, iris_L1, iris_cx, iris_cy, 0, 0, 0 ],
72 | #[display_R1, eyeball_R1, iris_R1, iris_cx, iris_cy, 0, 0, 0 ], # can't do four yet
73 | ]
74 |
75 |
76 | r = 17 # allowable deviation from center for iris
77 |
78 | while True:
79 | for i in range(len(the_eyes)):
80 | (display, eyeball, iris, x,y, tx,ty, next_time) = the_eyes[i]
81 | x = x * 0.5 + tx * 0.5 # "easing"
82 | y = y * 0.5 + ty * 0.5
83 | iris.x = int( x )
84 | iris.y = int( y )
85 | the_eyes[i][3] = x
86 | the_eyes[i][4] = y
87 | if time.monotonic() > next_time:
88 | next_time = time.monotonic() + random.uniform(0,2)
89 | tx = iris_cx + random.uniform(-r,r)
90 | ty = iris_cy + random.uniform(-r,r)
91 | the_eyes[i][5] = tx
92 | the_eyes[i][6] = ty
93 | the_eyes[i][7] = next_time # FIXME
94 | print("change!")
95 | #display.refresh( target_frames_per_second=20 )
96 | display.refresh()
97 |
--------------------------------------------------------------------------------
/examples/eyeballs/imgs/Lizard_Iris_White.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/eyeballs/imgs/Lizard_Iris_White.bmp
--------------------------------------------------------------------------------
/examples/eyeballs/imgs/Lizard_Sclera.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/eyeballs/imgs/Lizard_Sclera.bmp
--------------------------------------------------------------------------------
/examples/eyeballs/imgs/eye0_ball2.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/eyeballs/imgs/eye0_ball2.bmp
--------------------------------------------------------------------------------
/examples/eyeballs/imgs/eye0_iris0.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/eyeballs/imgs/eye0_iris0.bmp
--------------------------------------------------------------------------------
/examples/eyeballs/qteye.py:
--------------------------------------------------------------------------------
1 | # qteye.py - a stand-alone GC9A01 round LCD "eye" on a QTPy
2 | # 23 Oct 2022 - @todbot / Tod Kurt
3 | # Part of https://github.com/todbot/CircuitPython_GC9A01_demos
4 | # also see: https://twitter.com/todbot/status/1584309133263532033
5 | # and: https://twitter.com/todbot/status/1584309133263532033
6 | # Copy this file as "code.py" and the two eyeball BMP files to CIRCUITPY drive
7 | # To install needed libraries: "circup install adafruit_imageload gc9a01"
8 | #
9 | import time, math, random
10 | import board, busio
11 | import displayio
12 | import adafruit_imageload
13 | import gc9a01
14 |
15 | displayio.release_displays()
16 |
17 | dw, dh = 240,240 # display dimensions
18 |
19 | # load our eye and iris bitmaps
20 | eyeball_bitmap, eyeball_pal = adafruit_imageload.load("imgs/eye0_ball2.bmp")
21 | iris_bitmap, iris_pal = adafruit_imageload.load("imgs/eye0_iris0.bmp")
22 | iris_pal.make_transparent(0) # palette color #0 is our transparent background
23 |
24 | # compute or declare some useful info about the eyes
25 | iris_w, iris_h = iris_bitmap.width, iris_bitmap.height # iris is normally 110x110
26 | iris_cx, iris_cy = dw//2 - iris_w//2, dh//2 - iris_h//2
27 | r = 20 # allowable deviation from center for iris
28 |
29 | # wiring for QT Py, should work on any QT Py or XIAO board
30 | tft0_clk = board.SCK
31 | tft0_mosi = board.MOSI
32 |
33 | tft_L0_rst = board.MISO
34 | tft_L0_dc = board.RX
35 | tft_L0_cs = board.TX
36 |
37 | spi0 = busio.SPI(clock=tft0_clk, MOSI=tft0_mosi)
38 |
39 | # class to help us track eye info (not needed for this use exactly, but I find it interesting)
40 | class Eye:
41 | def __init__(self, spi, dc, cs, rst, rot=0, eye_speed=0.25, twitch=2):
42 | display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=rst)
43 | display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=rot)
44 | main = displayio.Group()
45 | display.show(main)
46 | self.display = display
47 | self.eyeball = displayio.TileGrid(eyeball_bitmap, pixel_shader=eyeball_pal)
48 | self.iris = displayio.TileGrid(iris_bitmap, pixel_shader=iris_pal, x=iris_cx,y=iris_cy)
49 | main.append(self.eyeball)
50 | main.append(self.iris)
51 | self.x, self.y = iris_cx, iris_cy
52 | self.tx, self.ty = self.x, self.y
53 | self.next_time = time.monotonic()
54 | self.eye_speed = eye_speed
55 | self.twitch = twitch
56 |
57 | def update(self):
58 | self.x = self.x * (1-self.eye_speed) + self.tx * self.eye_speed # "easing"
59 | self.y = self.y * (1-self.eye_speed) + self.ty * self.eye_speed
60 | self.iris.x = int( self.x )
61 | self.iris.y = int( self.y )
62 | if time.monotonic() > self.next_time:
63 | t = random.uniform(0.25,self.twitch)
64 | self.next_time = time.monotonic() + t
65 | self.tx = iris_cx + random.uniform(-r,r)
66 | self.ty = iris_cy + random.uniform(-r,r)
67 | self.display.refresh()
68 |
69 | # a list of all the eyes, in this case, only one
70 | the_eyes = [
71 | Eye( spi0, tft_L0_dc, tft_L0_cs, tft_L0_rst, rot=0),
72 | ]
73 |
74 | while True:
75 | for eye in the_eyes:
76 | eye.update()
77 |
--------------------------------------------------------------------------------
/examples/eyeballs/qteye_person_sensor.py:
--------------------------------------------------------------------------------
1 | # qteye_person_sensor.py -- quick hacking of Person Sensor by Useful Sensors onto qteye
2 | # 23 Oct 2022 - @todbot / Tod Kurt
3 | # Part of https://github.com/todbot/CircuitPython_GC9A01_demos
4 | # Also see: https://twitter.com/todbot/status/1584662808691896320
5 | #
6 | # For more information on Person Sensor:
7 | # https://github.com/usefulsensors/person_sensor_docs/blob/main/README.md
8 | # https://github.com/usefulsensors/person_sensor_screen_lock
9 | # https://www.hackster.io/petewarden/auto-lock-your-laptop-screen-with-a-person-sensor-7e0a35
10 | #
11 | # Copy this file as "code.py" and the two eyeball BMP files to CIRCUITPY drive
12 | # To install needed libraries: "circup install adafruit_imageload gc9a01"
13 | #
14 |
15 | import time, math, random, struct
16 | import board, busio
17 | import displayio
18 | import adafruit_imageload
19 | import gc9a01
20 |
21 | displayio.release_displays()
22 |
23 | debug_face = True
24 |
25 | dw, dh = 240,240 # display dimensions
26 |
27 | eyeball_bitmap, eyeball_pal = adafruit_imageload.load("imgs/eye0_ball2.bmp")
28 | iris_bitmap, iris_pal = adafruit_imageload.load("imgs/eye0_iris0.bmp")
29 | iris_pal.make_transparent(0) # palette color #0 is our transparent background
30 |
31 | iris_w, iris_h = iris_bitmap.width, iris_bitmap.height # iris is normally 110x110
32 | iris_cx, iris_cy = dw//2 - iris_w//2, dh//2 - iris_h//2
33 | r = 20 # allowable deviation from center for iris
34 |
35 | tft0_clk = board.SCK
36 | tft0_mosi = board.MOSI
37 |
38 | tft_L0_rst = board.MISO
39 | tft_L0_dc = board.RX
40 | tft_L0_cs = board.TX
41 |
42 | spi0 = busio.SPI(clock=tft0_clk, MOSI=tft0_mosi)
43 |
44 | class Eye:
45 | def __init__(self, spi, dc, cs, rst, rot=0, eye_speed=0.25, twitch=2):
46 | display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=rst)
47 | display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=rot)
48 | main = displayio.Group()
49 | display.show(main)
50 | self.display = display
51 | self.eyeball = displayio.TileGrid(eyeball_bitmap, pixel_shader=eyeball_pal)
52 | self.iris = displayio.TileGrid(iris_bitmap, pixel_shader=iris_pal, x = iris_cx, y = iris_cy )
53 | main.append(self.eyeball)
54 | main.append(self.iris)
55 | self.x, self.y = iris_cx, iris_cy
56 | self.tx, self.ty = self.x, self.y
57 | self.next_time = time.monotonic()
58 | self.eye_speed = eye_speed
59 | self.twitch = twitch
60 |
61 | def update(self, do_random=False, ntx=None, nty=None):
62 | self.x = self.x * (1-self.eye_speed) + self.tx * self.eye_speed # "easing"
63 | self.y = self.y * (1-self.eye_speed) + self.ty * self.eye_speed
64 | self.iris.x = int( self.x )
65 | self.iris.y = int( self.y )
66 |
67 | if ntx is not None and nty is not None:
68 | self.tx = iris_cx + ntx
69 | self.ty = iris_cx + nty
70 | else:
71 | if do_random and time.monotonic() > self.next_time:
72 | t = random.uniform(0.25,self.twitch)
73 | self.next_time = time.monotonic() + t
74 | self.tx = iris_cx + random.uniform(-r,r)
75 | self.ty = iris_cy + random.uniform(-r,r)
76 | print("change!",t )
77 | self.display.refresh()
78 |
79 | the_eye = Eye( spi0, tft_L0_dc, tft_L0_cs, tft_L0_rst, rot=0)
80 |
81 |
82 | i2c = board.STEMMA_I2C()
83 |
84 | # Wait until we can access the bus.
85 | while not i2c.try_lock():
86 | pass
87 |
88 | last_person_sensor_time = 0
89 | # Keep looping and reading the person sensor results.
90 | def get_faces():
91 | global last_person_sensor_time
92 |
93 | # The person sensor has the I2C ID of hex 62, or decimal 98.
94 | PERSON_SENSOR_I2C_ADDRESS = 0x62
95 |
96 | # We will be reading raw bytes over I2C, and we'll need to decode them into
97 | # data structures. These strings define the format used for the decoding, and
98 | # are derived from the layouts defined in the developer guide.
99 | PERSON_SENSOR_I2C_HEADER_FORMAT = "BBH"
100 | PERSON_SENSOR_I2C_HEADER_BYTE_COUNT = struct.calcsize(
101 | PERSON_SENSOR_I2C_HEADER_FORMAT)
102 |
103 | PERSON_SENSOR_FACE_FORMAT = "BBBBBBbB"
104 | PERSON_SENSOR_FACE_BYTE_COUNT = struct.calcsize(PERSON_SENSOR_FACE_FORMAT)
105 |
106 | PERSON_SENSOR_FACE_MAX = 4
107 | PERSON_SENSOR_RESULT_FORMAT = PERSON_SENSOR_I2C_HEADER_FORMAT + \
108 | "B" + PERSON_SENSOR_FACE_FORMAT * PERSON_SENSOR_FACE_MAX + "H"
109 | PERSON_SENSOR_RESULT_BYTE_COUNT = struct.calcsize(PERSON_SENSOR_RESULT_FORMAT)
110 |
111 | # How long to pause between sensor polls.
112 | PERSON_SENSOR_DELAY = 0.3
113 |
114 | # How large a face needs to be to count.
115 | MAIN_FACE_MIN_WIDTH = 16 # was 32
116 | MAIN_FACE_MIN_HEIGHT = 16
117 |
118 | if time.monotonic() - last_person_sensor_time < PERSON_SENSOR_DELAY:
119 | return []
120 | last_person_sensor_time = time.monotonic()
121 |
122 | read_data = bytearray(PERSON_SENSOR_RESULT_BYTE_COUNT)
123 | i2c.readfrom_into(PERSON_SENSOR_I2C_ADDRESS, read_data)
124 |
125 | offset = 0
126 | (pad1, pad2, payload_bytes) = struct.unpack_from(
127 | PERSON_SENSOR_I2C_HEADER_FORMAT, read_data, offset)
128 | offset = offset + PERSON_SENSOR_I2C_HEADER_BYTE_COUNT
129 |
130 | (num_faces) = struct.unpack_from("B", read_data, offset)
131 | num_faces = int(num_faces[0])
132 | offset = offset + 1
133 |
134 | faces = []
135 | for i in range(num_faces):
136 | (box_confidence, box_left, box_top, box_right, box_bottom, id_confidence, id,
137 | is_facing) = struct.unpack_from(PERSON_SENSOR_FACE_FORMAT, read_data, offset)
138 | offset = offset + PERSON_SENSOR_FACE_BYTE_COUNT
139 | face = {
140 | "box_confidence": box_confidence,
141 | "box_left": box_left,
142 | "box_top": box_top,
143 | "box_right": box_right,
144 | "box_bottom": box_bottom,
145 | "id_confidence": id_confidence,
146 | "id": id,
147 | "is_facing": is_facing,
148 | }
149 | faces.append(face)
150 | checksum = struct.unpack_from("H", read_data, offset)
151 |
152 | has_main_face = False
153 | has_lookie_loo = False
154 | for face in faces:
155 | width = face["box_right"] - face["box_left"]
156 | height = face["box_bottom"] - face["box_top"]
157 | big_enough_face = (
158 | width > MAIN_FACE_MIN_WIDTH and height > MAIN_FACE_MIN_HEIGHT)
159 | if big_enough_face:
160 | if not has_main_face:
161 | has_main_face = True
162 | else:
163 | if face["is_facing"] and face["box_confidence"] > 90:
164 | has_lookie_loo = True
165 |
166 | if debug_face: print("faces:",faces)
167 | return faces
168 |
169 | def map_range(s, a1, a2, b1, b2):
170 | return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
171 |
172 | while True:
173 | faces = []
174 | faces = get_faces()
175 |
176 | facex, facey = None,None
177 | if len(faces) > 0:
178 | facex0 = (faces[0]['box_right'] - faces[0]['box_left']) // 2 + faces[0]['box_left']
179 | facex = map_range(facex0, 0,255, 30,-30)
180 | facey = 0
181 | print("facex: ",facex0,facex)
182 |
183 | the_eye.update( ntx=facex, nty=facey )
184 |
--------------------------------------------------------------------------------
/examples/gc9a01_gauge_knob.py:
--------------------------------------------------------------------------------
1 | # gc9a01_dial_knob.py -- Demonstrate round LCD as a gauge, controlled by a pot knob
2 | #
3 | # 2021 - Tod Kurt - todbot.com
4 | #
5 | # Tested on QTPy RP2040, ItsyBitsy M4,
6 | # Raspberry Pi Pico (RP2040) running CircuitPython 7
7 | #
8 | # You'll need to install 'adafruit_display_text', 'adafruit_imageload'
9 | # and 'gc9a01' library.
10 | # Easiest way to do this is from Terminal:
11 | # circup install adafruit_display_text adafruit_imageload gc9a01
12 | #
13 |
14 | import time
15 | import math
16 | import board
17 | import busio
18 | import displayio
19 | import bitmaptools
20 | import terminalio
21 | from analogio import AnalogIn
22 | import adafruit_imageload
23 | from adafruit_display_text import label
24 | import gc9a01
25 |
26 | # change these as you like, keep the pointer center at 15,105
27 | dial_background_filename = '/imgs/dial-background.bmp'
28 | pointer_filename = '/imgs/pointer-red-basic-30x140-c15x105.bmp'
29 | legend_text = "PERCENT\nAWESOME"
30 |
31 | displayio.release_displays()
32 |
33 | import os
34 | board_type = os.uname().machine
35 |
36 | if 'QT Py M0' in board_type or 'QT Py RP2040' in board_type:
37 | # QT Py pinout
38 | tft_clk = board.SCK
39 | tft_mosi = board.MOSI
40 | tft_rst = board.TX
41 | tft_dc = board.RX
42 | tft_cs = board.A3
43 | tft_bl = board.A2 # optional
44 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
45 | elif 'ItsyBitsay M4' in board_type:
46 | tft_clk = board.SCK
47 | tft_mosi = board.MOSI
48 | tft_rst = board.MISO
49 | tft_dc = board.D2
50 | tft_cs = board.A5
51 | tft_bl = board.A3 # optional
52 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
53 | elif 'Pico' in board_type:
54 | # # one pinout, on "southeast" side of Pico board
55 | # tft_clk = board.GP18
56 | # tft_mosi= board.GP19
57 | # tft_rst = board.GP20
58 | # tft_dc = board.GP16
59 | # tft_cs = board.GP17
60 | # tft_bl = board.GP21
61 | # spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
62 |
63 | # another pinout, on "southwest" of Pico board
64 | tft_clk = board.GP10
65 | tft_mosi= board.GP11
66 | tft_rst = board.GP12
67 | tft_dc = board.GP13
68 | tft_cs = board.GP14
69 | tft_bl = board.GP15
70 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
71 | elif 'Waveshare RP2040-LCD-1.28 with rp2040' in board_type:
72 | tft_clk = board.LCD_CLK
73 | tft_mosi = board.LCD_DIN
74 | tft_rst = board.LCD_RST
75 | tft_dc = board.LCD_DC
76 | tft_cs = board.LCD_CS
77 | tft_bl = board.LCD_BL
78 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
79 |
80 | # Analog knob to control dial
81 | analog_in = AnalogIn(board.A1)
82 |
83 | # Create displayio bus and display
84 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
85 | display = gc9a01.GC9A01(display_bus, width=240, height=240,
86 | backlight_pin=tft_bl, auto_refresh=False)
87 |
88 | # Create main display group and add it to the display
89 | main = displayio.Group()
90 | display.root_group = main
91 |
92 | # 240x240 dial background
93 | bg_bitmap,bg_pal = adafruit_imageload.load(dial_background_filename)
94 | bg_tile_grid = displayio.TileGrid(bg_bitmap, pixel_shader=bg_pal)
95 | main.append(bg_tile_grid)
96 |
97 | # Text legend
98 | text_area = label.Label(terminalio.FONT, text=legend_text, line_spacing=0.9, color=0x000000, anchor_point=(0.5,0.5), anchored_position=(0,0))
99 | text_group = displayio.Group(scale=1, x=120, y=155)
100 | text_group.append(text_area)
101 | main.append(text_group) # Subgroup for text scaling
102 |
103 | # 30x140 pointer
104 | bitmap_pointer, palette_pointer = adafruit_imageload.load(pointer_filename, bitmap=displayio.Bitmap,palette=displayio.Palette)
105 | palette_pointer.make_transparent(0)
106 |
107 | # Blank bitmap the same size as the pointer bitmap
108 | bitmap_pointer_blank = displayio.Bitmap(bitmap_pointer.width, bitmap_pointer.height, 1)# len(palette_pointer))
109 | #bitmap_pointer_blank.fill(0)
110 |
111 | # Transparent overlay that is "scribbled" into by rotozoom
112 | # to create rotated version of pointer
113 | bitmap_scribble = displayio.Bitmap(display.width, display.height, len(palette_pointer))
114 | tile_grid = displayio.TileGrid(bitmap_scribble, pixel_shader=palette_pointer)
115 | main.append(tile_grid)
116 |
117 | # Do initial draw
118 | display.refresh()
119 |
120 | print("Hello World!")
121 |
122 | # simple range mapper, like Arduino map()
123 | def map_range(s, a, b):
124 | (a1, a2), (b1, b2) = a, b
125 | return b1 + ((s - a1) * (b2 - b1) / (a2 - a1))
126 |
127 | # for dial 'dial-percenti.bmp', range is kinda:
128 | # 0% - 100% => + 2.6 - -2.6
129 | def percent_to_theta(p):
130 | return map_range(p, (0.0,1.0), (-2.6, 2.6) )
131 |
132 | percent = 0.0
133 | last_time = time.monotonic()
134 | while True:
135 | percent = map_range( analog_in.value, (200,65400), (1,0))
136 | theta = percent_to_theta(percent)
137 |
138 | print("dt:",time.monotonic()-last_time,"theta:", theta, int(percent*100))
139 | last_time = time.monotonic()
140 |
141 | # erasing the entire bitmap is slow (~1fps, because of transparency I think)
142 | # instead we erase just the region we modified, after refresh below
143 | # bitmap_scribble.fill(0)
144 |
145 | # offset rotation point (15,105) for bitmap_pointer's axis of rotation
146 | bitmaptools.rotozoom( bitmap_scribble, bitmap_pointer, angle = theta, px=15,py=105)
147 |
148 | display.refresh()
149 |
150 | # after refresh, now "erase" the rotated pointer by doing a
151 | # rotozom of a "blank" bitmap with only transparency
152 | bitmaptools.rotozoom( bitmap_scribble, bitmap_pointer_blank, angle = theta, px=15,py=105)
153 |
--------------------------------------------------------------------------------
/examples/gc9a01_hellocircles.py:
--------------------------------------------------------------------------------
1 | #
2 | # gc9a01_hellocircles.py -- Simple Demo of GC9A01 Round LCD
3 | #
4 | # 2021 - Tod Kurt - todbot.com
5 | #
6 | # Tested on QTPy M0 (SAMD21), QTPy RP2040, ItsyBitsy M4,
7 | # Raspberry Pi Pico (RP2040) running CircuitPython 7.
8 | #
9 | # You'll need to install 'adafruit_display_text' and 'gc9a01' library.
10 | # Easiest way to do this is from Terminal:
11 | # circup install adafruit_display_text gc9a01
12 | #
13 |
14 | import time
15 | import board
16 | import math
17 | import random
18 | import busio
19 | import terminalio
20 | import displayio
21 | from vectorio import Rectangle, Circle, Polygon
22 | from adafruit_display_text import label
23 | import gc9a01
24 |
25 | # Release any resources currently in use for the displays
26 | displayio.release_displays()
27 |
28 | # attempt to auto-detect board type
29 | import os
30 | board_type = os.uname().machine
31 |
32 | if 'QT Py M0 Haxpress' in board_type or 'QT Py RP2040' in board_type:
33 | tft_clk = board.SCK
34 | tft_mosi = board.MOSI
35 | tft_rst = board.TX
36 | tft_dc = board.RX
37 | tft_cs = board.A3
38 | tft_bl = board.A2
39 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
40 | elif 'Adafruit Feather M4 Express with samd51j19' in board_type:
41 | tft_clk = board.SCL
42 | tft_mosi = board.SDA
43 | tft_rst = board.D9
44 | tft_dc = board.D6
45 | tft_cs = board.D5
46 | tft_bl = board.A3 # optional
47 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
48 | elif 'ItsyBitsy M4' in board_type:
49 | tft_clk = board.SCK
50 | tft_mosi = board.MOSI
51 | tft_rst = board.MISO
52 | tft_dc = board.D2
53 | tft_cs = board.A5
54 | tft_bl = board.A3 # optional
55 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
56 | elif 'Pico' in board_type:
57 | # Raspberry Pi Pico pinout, one possibility, at "southwest" of board
58 | tft_clk = board.GP10 # must be a SPI CLK
59 | tft_mosi= board.GP11 # must be a SPI TX
60 | tft_rst = board.GP12
61 | tft_dc = board.GP13
62 | tft_cs = board.GP14
63 | tft_bl = board.GP15
64 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
65 | elif 'Waveshare RP2040-LCD-1.28 with rp2040' in board_type:
66 | tft_clk = board.LCD_CLK
67 | tft_mosi = board.LCD_DIN
68 | tft_rst = board.LCD_RST
69 | tft_dc = board.LCD_DC
70 | tft_cs = board.LCD_CS
71 | tft_bl = board.LCD_BL
72 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
73 | else:
74 | print("ERROR: Unknown board!")
75 |
76 | # Make the displayio SPI bus and the GC9A01 display
77 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
78 | display = gc9a01.GC9A01(display_bus, width=240, height=240, backlight_pin=tft_bl)
79 |
80 | # Make the main display context
81 | main = displayio.Group()
82 | display.root_group = main
83 |
84 | for i in range(15):
85 | sx = random.randint(0, 240)
86 | sy = random.randint(0, 240)
87 | circ_palette = displayio.Palette(1)
88 | circ_palette[0] = (random.randint(0,0xFF), 0, random.randint(0,0xFF))
89 | main.append(Circle(pixel_shader=circ_palette, radius=30, x=sx, y=sy))
90 |
91 | # Draw a text label
92 | text = "Hello\nWorld!"
93 | text_area = label.Label(terminalio.FONT, text=text, color=0xFFFF00,
94 | anchor_point=(0.5,0.5), anchored_position=(0,0))
95 | text_group = displayio.Group(scale=2)
96 | text_group.append(text_area)
97 | main.append(text_group)
98 |
99 | display.auto_refresh = False
100 | # Animate the text
101 | theta = math.pi
102 | r = 75
103 | while True:
104 | print(time.monotonic(),"hello")
105 | i = random.randint(0,15)
106 | main[i].x = (main[i].x + 5) % 240
107 | text_group.x = 120 + int(r * math.sin(theta))
108 | text_group.y = 120 + int(r * math.cos(theta))
109 | display.refresh()
110 | theta -= 0.05
111 | time.sleep(0.01)
112 |
--------------------------------------------------------------------------------
/examples/gc9a01_hellocircles_pico_compact.py:
--------------------------------------------------------------------------------
1 | import time, math, random
2 | import board, busio
3 | import displayio, terminalio
4 | import rainbowio, vectorio
5 | import gc9a01
6 | from adafruit_display_text import bitmap_label as label
7 |
8 | dw,dh = 240,240 # display width,height
9 |
10 | displayio.release_displays()
11 | # Raspberry Pi Pico pinout, one possibility, at "southeast" of board
12 | tft_clk = board.GP18 # must be a SPI CLK
13 | tft_mosi= board.GP19 # must be a SPI TX
14 | tft_rst = board.GP21
15 | tft_dc = board.GP16
16 | tft_cs = board.GP17
17 |
18 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
19 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
20 | display = gc9a01.GC9A01(display_bus, width=dw, height=dh, rotation=270)
21 | maingroup = displayio.Group() # a main group that holds everything
22 | display.root_group = maingroup # put it on the display
23 |
24 | # draw cirlces
25 | for i in range(15):
26 | sx = random.randint(0, dw)
27 | sy = random.randint(0, dh)
28 | pal = displayio.Palette(1)
29 | pal[0] = rainbowio.colorwheel( random.randint(180,240) ) # 240 is a coincidence here
30 | #s0 = vectorio.Circle(pixel_shader=pal0, radius=30, x=sx, y=sy)
31 | s0 = vectorio.Circle(pixel_shader=pal, radius=30, x=sx, y=sy)
32 | maingroup.append(s0)
33 |
34 | # Draw a text label
35 | text_area = label.Label(terminalio.FONT, text="Hellow\nWorld!", color=0xFFFF00, scale=2,
36 | anchor_point=(0.5,0.5), anchored_position=(0,0))
37 | text_group = displayio.Group() # put in a group so anchor_position works correctly
38 | text_group.append(text_area)
39 | maingroup.append(text_group)
40 |
41 | # Animate the text
42 | theta = math.pi
43 | r = 75
44 | while True:
45 | print(time.monotonic(),"hello")
46 | i = random.randint(0,15)
47 | maingroup[i].x = (maingroup[i].x + 5) % 240
48 | text_group.x = 120 + int(r * math.sin(theta))
49 | text_group.y = 120 + int(r * math.cos(theta))
50 | display.refresh( target_frames_per_second=20 )
51 | theta -= 0.05
52 |
53 |
--------------------------------------------------------------------------------
/examples/gc9a01_helloworld.py:
--------------------------------------------------------------------------------
1 | #
2 | # gc9a01_helloworld.py -- Simple Demo of GC9A01 Round LCD
3 | #
4 | # 2021 - Tod Kurt - todbot.com
5 | #
6 | # Tested on QTPy M0 (SAMD21), QTPy RP2040, ItsyBitsy M4,
7 | # Raspberry Pi Pico (RP2040) running CircuitPython 7
8 | #
9 | # You'll need to install 'adafruit_display_text' and 'gc9a01' library.
10 | # Easiest way to do this is from Terminal:
11 | # circup install adafruit_display_text gc9a01
12 | #
13 |
14 | import time
15 | import board
16 | import math
17 | import busio
18 | import terminalio
19 | import displayio
20 | from adafruit_display_text import label
21 | import gc9a01
22 |
23 | # Release any resources currently in use for the displays
24 | displayio.release_displays()
25 |
26 | # attempt to auto-detect board type
27 | import os
28 | board_type = os.uname().machine
29 |
30 | if 'QT Py M0' in board_type or 'QT Py RP2040' in board_type:
31 | # QT Py pinout
32 | tft_clk = board.SCK
33 | tft_mosi = board.MOSI
34 | tft_rst = board.TX
35 | tft_dc = board.RX
36 | tft_cs = board.A3
37 | tft_bl = board.A2
38 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
39 | # spi.try_lock()
40 | # spi.configure(baudrate=12_000_000) # default spi is 0.25MHz on QT Py, try 12MHz
41 | # spi.unlock()
42 | elif 'ItsyBitsy M4' in board_type:
43 | # Itsy M4 pinout
44 | tft_clk = board.SCK
45 | tft_mosi = board.MOSI
46 | tft_rst = board.MISO
47 | tft_dc = board.D2
48 | tft_cs = board.A5
49 | tft_bl = board.A3 # optional
50 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
51 | elif 'Pico' in board_type:
52 | # Raspberry Pi Pico pinout, one possibility, at "southwest" of board
53 | tft_clk = board.GP10 # must be a SPI CLK
54 | tft_mosi= board.GP11 # must be a SPI TX
55 | tft_rst = board.GP12
56 | tft_dc = board.GP13
57 | tft_cs = board.GP14
58 | tft_bl = board.GP15
59 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
60 | elif 'Waveshare RP2040-LCD-1.28 with rp2040' in board_type:
61 | tft_clk = board.LCD_CLK
62 | tft_mosi = board.LCD_DIN
63 | tft_rst = board.LCD_RST
64 | tft_dc = board.LCD_DC
65 | tft_cs = board.LCD_CS
66 | tft_bl = board.LCD_BL
67 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
68 | else:
69 | print("ERROR: Unknown board!")
70 |
71 | # Make the displayio SPI bus and the GC9A01 display
72 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
73 | display = gc9a01.GC9A01(display_bus, width=240, height=240, backlight_pin=tft_bl)
74 |
75 | # Make the main display context
76 | main = displayio.Group()
77 | display.root_group = main
78 |
79 | # Draw a text label
80 | text = "Hello\nWorld!"
81 | text_area = label.Label(terminalio.FONT, text=text, color=0xFFFF00,
82 | anchor_point=(0.5,0.5), anchored_position=(0,0))
83 | text_group = displayio.Group(scale=2)
84 | text_group.append(text_area)
85 | main.append(text_group)
86 |
87 | # Animate the text
88 | theta = math.pi
89 | r = 75
90 | while True:
91 | print(time.monotonic(),"hello")
92 | text_group.x = 120 + int(r * math.sin(theta))
93 | text_group.y = 120 + int(r * math.cos(theta))
94 | theta -= 0.05
95 | time.sleep(0.01)
96 |
--------------------------------------------------------------------------------
/examples/gc9a01_picture_locket.py:
--------------------------------------------------------------------------------
1 | #
2 | # gc9a01_picture_locket.py -- Simple Demo of GC9A01 Round LCD
3 | #
4 | # 2021 - Tod Kurt - todbot.com
5 | #
6 | # Tested on QTPy (SAMD21), QTPy RP2040, and Raspberry Pi Pico (RP2040)
7 | # running CircuitPython 7.
8 | #
9 | # You'll need to install 'gc9a01' package.
10 | # Easiest way to do this is from Terminal:
11 | # circup install gc9a01
12 | #
13 |
14 | import time
15 | import board
16 | import math
17 | import busio
18 | import terminalio
19 | import displayio
20 | import adafruit_imageload
21 | import gc9a01
22 |
23 | # A list of all the BMP images you want displayed, in order
24 | #
25 | # prepare image with ImageMagick like:
26 | # convert input.jpg -resize 240x240 -type palette BMP3:output.bmp
27 | img_filenames = ( "/imgs/max1.bmp",
28 | "/imgs/lars240.bmp" )
29 |
30 | # time in seconds between images
31 | img_time = 10
32 |
33 | # Release any resources currently in use for the displays
34 | displayio.release_displays()
35 |
36 | # attempt to auto-detect board type
37 | import os
38 | board_type = os.uname().machine
39 | if 'QT Py M0 Haxpress' in board_type or 'QT Py RP2040' in board_type:
40 | tft_clk = board.SCK
41 | tft_mosi = board.MOSI
42 | tft_rst = board.TX
43 | tft_dc = board.RX
44 | tft_cs = board.A3
45 | tft_bl = board.A2
46 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
47 | elif 'ItsyBitsy M4' in board_type:
48 | tft_clk = board.SCK
49 | tft_mosi = board.MOSI
50 | tft_rst = board.MISO
51 | tft_dc = board.D2
52 | tft_cs = board.A5
53 | tft_bl = board.A3 # optional
54 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
55 | elif 'Pico' in board_type:
56 | # Raspberry Pi Pico pinout, one possibility, at "southwest" of board
57 | tft_clk = board.GP10 # must be a SPI CLK
58 | tft_mosi= board.GP11 # must be a SPI TX
59 | tft_rst = board.GP12
60 | tft_dc = board.GP13
61 | tft_cs = board.GP14
62 | tft_bl = board.GP15
63 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
64 | elif 'Waveshare RP2040-LCD-1.28 with rp2040' in board_type:
65 | tft_clk = board.LCD_CLK
66 | tft_mosi = board.LCD_DIN
67 | tft_rst = board.LCD_RST
68 | tft_dc = board.LCD_DC
69 | tft_cs = board.LCD_CS
70 | tft_bl = board.LCD_BL
71 | spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
72 | else:
73 | print("ERROR: Unknown board!")
74 |
75 | # Make the displayio SPI bus and the GC9A01 display
76 | display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
77 | display = gc9a01.GC9A01(display_bus, width=240, height=240, backlight_pin=tft_bl)
78 |
79 | # Make the main display context
80 | main = displayio.Group()
81 | display.root_group = main
82 |
83 | i=0
84 | while True:
85 | print(time.monotonic(),"hello")
86 | img_filename = img_filenames[i]
87 | img_bitmap = displayio.OnDiskBitmap(open(img_filename, "rb"))
88 | img_palette = displayio.ColorConverter()
89 | #img_bitmap, img_palette = adafruit_imageload.load(img_filename)
90 | img_tilegrid = displayio.TileGrid(img_bitmap, pixel_shader=img_palette)
91 | main.append(img_tilegrid)
92 | time.sleep(img_time)
93 | main.pop() # remove image
94 | i = (i+1) % len(img_filenames) # go to next file
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/examples/imgs/dial-background.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/dial-background.bmp
--------------------------------------------------------------------------------
/examples/imgs/dial-percenti.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/dial-percenti.bmp
--------------------------------------------------------------------------------
/examples/imgs/lars240.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/lars240.bmp
--------------------------------------------------------------------------------
/examples/imgs/max1.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/max1.bmp
--------------------------------------------------------------------------------
/examples/imgs/max2.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/max2.bmp
--------------------------------------------------------------------------------
/examples/imgs/pointer-red-basic-30x140-c15x105.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/pointer-red-basic-30x140-c15x105.bmp
--------------------------------------------------------------------------------
/examples/imgs/pointer-red-basic-30x140.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/todbot/CircuitPython_GC9A01_demos/877c351620a2d21fcbd5fdb2ae3ea523030e1ffd/examples/imgs/pointer-red-basic-30x140.bmp
--------------------------------------------------------------------------------
/examples/pico_boot.py:
--------------------------------------------------------------------------------
1 | # Copy this as 'boot.py' in your Pico's CIRCUITPY drive
2 | # from https://gist.github.com/Neradoc/8056725be1c209475fd09ffc37c9fad4
3 | # Useful in case Pico locks up (which it's done a few times on me)
4 | #
5 | import board
6 | import time
7 | from digitalio import DigitalInOut,Pull
8 |
9 | import time
10 | led = DigitalInOut(board.LED)
11 | led.switch_to_output()
12 |
13 | safe = DigitalInOut(board.GP14)
14 | safe.switch_to_input(Pull.UP)
15 |
16 | def reset_on_pin():
17 | if safe.value is False:
18 | import microcontroller
19 | microcontroller.on_next_reset(microcontroller.RunMode.SAFE_MODE)
20 | microcontroller.reset()
21 |
22 | led.value = False
23 | for x in range(16):
24 | reset_on_pin()
25 | led.value = not led.value
26 | time.sleep(0.1)
27 |
--------------------------------------------------------------------------------
/old_driver/todbot_gc9a01.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: 2021 Tod Kurt
2 | #
3 | # SPDX-License-Identifier: MIT
4 |
5 | """
6 | `todbot_gc9a01`
7 | ====================================================
8 |
9 | Display driver for GC9A01
10 |
11 | * Author(s): Tod Kurt
12 |
13 | Implementation Notes
14 | --------------------
15 |
16 | **Hardware:**
17 | * GC9A01 round display 240x240
18 |
19 | **Software and Dependencies:**
20 |
21 | * Adafruit CircuitPython firmware for the supported boards:
22 | https://github.com/adafruit/circuitpython/releases
23 |
24 | """
25 |
26 | import displayio
27 |
28 | #__version__ = "1.0.0"
29 | #__repo__ = "https://github.com/todbot/todbot_CircuitPython_GC9A01.git"
30 |
31 | _INIT_SEQUENCE = (
32 | #xb"\x01\x80\x80" # Software reset then delay x80 (128ms)
33 | b"\xEF\x00"
34 | b"\xEB\x01\x14"
35 | b"\xFE\x00"
36 | b"\xEF\x00"
37 | b"\xEB\x01\x14"
38 | b"\x84\x01\x40"
39 | b"\x85\x01\xFF"
40 | b"\x86\x01\xFF"
41 | b"\x87\x01\xFF"
42 | b"\x88\x01\x0A"
43 | b"\x89\x01\x21"
44 | b"\x8A\x01\x00"
45 | b"\x8B\x01\x80"
46 | b"\x8C\x01\x01"
47 | b"\x8D\x01\x01"
48 | b"\x8E\x01\xFF"
49 | b"\x8F\x01\xFF"
50 | b"\xB6\x02\x00\x00"
51 | b"\x36\x01\x48" # orientation, x18,x28,x48,x88
52 | b"\x3A\x01\x05" # color mode, 18-bit = x06
53 | b"\x90\x04\x08\x08\x08\x08"
54 | b"\xBD\x01\x06"
55 | b"\xBC\x01\x00"
56 | b"\xFF\x03\x60\x01\x04"
57 | b"\xC3\x03\x13\xC4\x13"
58 | b"\xC9\x01\x22"
59 | b"\xBE\x01\x11"
60 | b"\xE1\x02\x10\x0E"
61 | b"\xDF\x03\x21\x0C\x02"
62 | b"\xF0\x06\x45\x09\x08\x08\x26\x2A"
63 | b"\xF1\x06\x43\x70\x72\x36\x37\x6F"
64 | b"\xF2\x06\x45\x09\x08\x08\x26\x2A"
65 | b"\xF3\x06\x43\x70\x72\x36\x37\x6F"
66 | b"\xED\x02\x1B\x0B"
67 | b"\xAE\x01\x77"
68 | b"\xCD\x01\x63"
69 | b"\x70\x09\x07\x07\x04\x0E\x0F\x09\x07\x08\x03"
70 | b"\xE8\x01\x34"
71 | b"\x62\x0C\x18\x0D\x71\xED\x70\x70\x18\x0F\x71\xEF\x70\x70"
72 | b"\x63\x0C\x18\x11\x71\xF1\x70\x70\x18\x13\x71\xF3\x70\x70"
73 | b"\x64\x07\x28\x29\xF1\x01\xF1\x00\x07"
74 | b"\x66\x0A\x3C\x00\xCD\x67\x45\x45\x10\x00\x00\x00"
75 | b"\x67\x0A\x00\x3C\x00\x00\x00\x01\x54\x10\x32\x98"
76 | b"\x74\x07\x10\x85\x80\x00\x00\x4E\x00"
77 | b"\x98\x02\x3E\x07"
78 | b"\x35\x00"
79 | b"\x21\x00"
80 | b"\x11\x80\x78"
81 | b"\x29\x80\x10"
82 | )
83 |
84 | #define COLOR_MODE 0x3A
85 | #define COLOR_MODE__12_BIT 0x03
86 | #define COLOR_MODE__16_BIT 0x05
87 | #define COLOR_MODE__18_BIT 0x06
88 |
89 |
90 | # pylint: disable=too-few-public-methods
91 | class GC9A01(displayio.Display):
92 | """GC9A01 display driver"""
93 |
94 | def __init__(self, bus, **kwargs):
95 | super().__init__(bus, _INIT_SEQUENCE, **kwargs)
96 |
97 |
--------------------------------------------------------------------------------