Skip to content

Added the ST7735 Display Driver #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Apr 3, 2019
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ install:
- pip install --force-reinstall pylint==1.9.2

script:
- pylint adafruit_st7735.py
- pylint adafruit_st7735/*.py
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-st7735 --library_location .
- cd docs && sphinx-build -E -W -b html . _build/html && cd ..
4 changes: 2 additions & 2 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Examples of unacceptable behavior by participants include:

The goal of the standards and moderation guidelines outlined here is to build
and maintain a respectful community. We ask that you don’t just aim to be
"technically unimpeachable", but rather try to be your best self.
"technically unimpeachable", but rather try to be your best self.

We value many things beyond technical expertise, including collaboration and
supporting others within our community. Providing a positive experience for
Expand Down Expand Up @@ -72,7 +72,7 @@ You may report in the following ways:
In any situation, you may send an email to <[email protected]>.

On the Adafruit Discord, you may send an open message from any channel
to all Community Helpers by tagging @community helpers. You may also send an
to all Community Helpers by tagging @community moderators. You may also send an
open message from any channel, or a direct message to @kattni#1507,
@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or
@Andon#8175.
Expand Down
5 changes: 3 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ Usage Example
=============

.. code-block:: python
import adafruit_st7735

from adafruit_st7735 import ST7735
import board
import busio
import displayio
Expand All @@ -39,7 +40,7 @@ Usage Example

spi = busio.SPI(board.SCL, board.SDA)
bus = displayio.FourWire(spi, chip_select=board.D9, command=board.D7, reset=board.D8)
display = adafruit_st7735.ST7735(bus, width=128, height=128)
display = ST7735(bus, width=128, height=128)

s = displayio.Shape(10, 10)
p = displayio.Palette(2)
Expand Down
74 changes: 74 additions & 0 deletions adafruit_st7735/st7735b.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# The MIT License (MIT)
#
# Copyright (c) 2019 Scott Shawcroft and Melissa LeBlanc-Williams
# for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_st7735.st7735b`
====================================================

Displayio driver for ST7735B based displays.

* Author(s): Melissa LeBlanc-Williams

Implementation Notes
--------------------

**Hardware:**

**Software and Dependencies:**

* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases

"""

import displayio

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ST7735.git"

_INIT_SEQUENCE = (
b"\x01\x80\x32" # _SWRESET and Delay 50ms
b"\x11\x80\xFF" # _SLPOUT
b"\x3A\x81\x05\x0A" # _COLMOD
b"\xB1\x83\x00\x06\x03\x0A" # _FRMCTR1
b"\x36\x01\x08" # _MADCTL
b"\xB6\x02\x15\x02" # _DISSET5
#1 clk cycle nonoverlap, 2 cycle gate, rise, 3 cycle osc equalize, Fix on VTL
b"\xB4\x01\x00" # _INVCTR line inversion
b"\xC0\x82\x02\x70\x0A" # _PWCTR1 GVDD = 4.7V, 1.0uA, 10 ms delay
b"\xC1\x01\x05" # _PWCTR2 VGH = 14.7V, VGL = -7.35V
b"\xC2\x02\x01\x02" # _PWCTR3 Opamp current small, Boost frequency
b"\xC5\x82\x3C\x38\x0A" # _VMCTR1
b"\xFC\x02\x11\x15" # _PWCTR6
b"\xE0\x10\x09\x16\x09\x20\x21\x1B\x13\x19\x17\x15\x1E\x2B\x04\x05\x02\x0E" # _GMCTRP1 Gamma
b"\xE1\x90\x0B\x14\x08\x1E\x22\x1D\x18\x1E\x1B\x1A\x24\x2B\x06\x06\x02\x0F\x0A" # _GMCTRN1
b"\x2a\x00\x02\x00\x81" # _CASET
b"\x2b\x00\x02\x00\x81" # _RASET
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't need to set the column and row, because that is going to be done by displayio every time it actually sends anything to the display (the Arduino driver needs it, because it only sets the column and row once at the beginning, and then sends the whole screen every time).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed.

b"\x13\x80\x0a" # _NORON
b"\x29\x80\xFF" # _DISPON
)

# pylint: disable=too-few-public-methods
class ST7735B(displayio.Display):
"""ST7735 driver for ST7735B"""
def __init__(self, bus, **kwargs):
super().__init__(bus, _INIT_SEQUENCE, **kwargs)
52 changes: 32 additions & 20 deletions adafruit_st7735.py → adafruit_st7735/st7735r.py
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# The MIT License (MIT)
#
# Copyright (c) 2019 Scott Shawcroft for Adafruit Industries LLC
# Copyright (c) 2019 Scott Shawcroft and Melissa LeBlanc-Williams
# for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand All @@ -20,20 +21,28 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_ST7735`
`adafruit_st7735.st7735r`
====================================================

Displayio driver for ST7735 based displays.
Displayio driver for ST7735R based displays.

* Author(s): Scott Shawcroft
* Author(s): Scott Shawcroft and Melissa LeBlanc-Williams

Implementation Notes
--------------------

**Hardware:**

.. todo:: Add links to any specific hardware product page(s), or category page(s). Use unordered list & hyperlink rST
inline format: "* `Link Text <url>`_"
* 1.8" SPI TFT display, 160x128 18-bit color:
https://www.adafruit.com/product/618
* Adafruit 0.96" 160x80 Color TFT Display w/ MicroSD Card Breakout:
https://www.adafruit.com/product/3533
* 1.8" Color TFT LCD display with MicroSD Card Breakout:
https://www.adafruit.com/product/358
* Adafruit 1.44" Color TFT LCD Display with MicroSD Card breakout:
https://www.adafruit.com/product/2088
* Adafruit Mini Color TFT with Joystick FeatherWing:
https://www.adafruit.com/product/3321

**Software and Dependencies:**

Expand All @@ -47,35 +56,38 @@
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ST7735.git"


_INIT_SEQUENCE = (
b"\x01\x80\x96" # SWRESET
b"\x11\x80\xff" # SLPOUT
_INIT_SEQUENCE = bytearray(
b"\x01\x80\x96" # SWRESET and Delay 150ms
b"\x11\x80\xff" # SLPOUT and Delay
b"\xb1\x03\x01\x2C\x2D" # _FRMCTR1
b"\xb2\x03\x01\x2C\x2D" #
b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D"
b"\xb2\x03\x01\x2C\x2D" # _FRMCTR2
b"\xb3\x06\x01\x2C\x2D\x01\x2C\x2D" # _FRMCTR3
b"\xb4\x01\x07" # _INVCTR line inversion
b"\xc0\x03\xa2\x02\x84" # _PWCTR1 GVDD = 4.7V, 1.0uA
b"\xc1\x01\xc5" # _PWCTR2 VGH=14.7V, VGL=-7.35V
b"\xc2\x02\x0a\x00" # _PWCTR3 Opamp current small, Boost frequency
b"\xc3\x02\x8a\x2a"
b"\xc4\x02\x8a\xee"
b"\xc5\x01\x0e" # _VMCTR1 VCOMH = 4V, VOML = -1.1V
b"\x2a\x00" # _INVOFF
b"\x20\x00" # _INVOFF
b"\x36\x01\x18" # _MADCTL bottom to top refresh
# 1 clk cycle nonoverlap, 2 cycle gate rise, 3 sycle osc equalie,
# fix on VTL
b"\x3a\x01\x05" # COLMOD - 16bit color
b"\xe0\x10\x02\x1c\x07\x12\x37\x32\x29\x2d\x29\x25\x2B\x39\x00\x01\x03\x10" # _GMCTRP1 Gamma
b"\xe1\x10\x03\x1d\x07\x06\x2E\x2C\x29\x2D\x2E\x2E\x37\x3F\x00\x00\x02\x10" # _GMCTRN1
b"\x2a\x03\x02\x00\x81" # _CASET XSTART = 2, XEND = 129
b"\x2b\x03\x02\x00\x81" # _RASET XSTART = 2, XEND = 129
b"\x13\x80\x0a" # _NORON
b"\x29\x80\x64" # _DISPON
)

class ST7735(displayio.Display):
"""ST7735 driver for ST7735R Green tabs"""
# TODO(tannewt): Add support for Red tabs and non-R chips. https://github.com/adafruit/Adafruit-ST7735-Library/blob/master/Adafruit_ST7735.cpp
def __init__(self, bus, *, width, height):
super().__init__(bus, _INIT_SEQUENCE, width=width, height=height, colstart=2)
# pylint: disable=too-few-public-methods
class ST7735R(displayio.Display):
"""ST7735 driver for ST7735R"""
def __init__(self, bus, *, init=None, **kwargs):
"""
:param bytes init: (Optional) An extra init sequence to append (default=None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this init argument because it leaks the binary blob init stuff. Display already has a rotation kwarg that can be used for rotation. (It's very slow for OnDiskBitmaps atm but we can improve it later.) If we also need a toggle for RGB or BGR then let's add it explicitly rather than generically.

By using Display for rotation we align our display memory accesses with the native refresh direction and make it easier to make updates tear-free in the future.

Advanced users can always use the display bus themselves to send extra commands too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the rotation doesn’t work for some displays like the 3.5 FeatherWing. Also, this was written before I dug into the actual CP code and now that I’m more comfortable with that, making some changes shouldn’t be a problem.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far in my testing, only a few displays needed to be initialized as BGR. The only driver that was complicated though was this one. This particular parameter is a little messy since it's also combined with the display rotation. There's 3 ways of doing this that I can see:

  1. Add a BGR parameter to the init function in the driver itself that adds an init code with the default rotation but sets BGR if true and make use of the rotation option in the driver.
  2. Make changes to the way the colors are converted if this flag is toggled when they are 565 encoded as BGR instead of RGB. I don't know if colors are always converted, so if they're not this may not work.
  3. Attempt to run the command inside of CP with default rotation if BGR is passed. This option could get messy for non-MIPI displays.

Personally my favorite option is #1 because the change is only in the driver. #2 is my second favorite, but I'm not sure if it will always work. #3 seems a bit sketchy and doesn't provide much benefit over #1, and is less flexible.

Another idea is we could always start with option #1 and implement option #2 after 4.0 stable is released.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like 1 but want to avoid MADCTL for rotation because it only impacts the memory access orientation, not screen refresh. If we always allow displayio to rotate "in software" rather than using MADCTL we can ensure our memory updates align with screen updates. This also means we can know in what direction the hardware scrolling of the display occurs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, which is why I’m only using MADCTL for BGR vs RGB and leaving rotation at default.

"""
init_sequence = _INIT_SEQUENCE
if init is not None:
init_sequence += init
super().__init__(bus, init_sequence, **kwargs)
5 changes: 4 additions & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
.. If your library file(s) are nested in a directory (e.g. /adafruit_foo/foo.py)
.. use this format as the module name: "adafruit_foo.foo"

.. automodule:: adafruit_st7735
.. automodule:: adafruit_st7735.st7735r
:members:

.. automodule:: adafruit_st7735.st7735b
:members:
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# digitalio, micropython and busio. List the modules you use. Without it, the
# autodoc module docs will fail to generate with a warning.
# autodoc_mock_imports = ["digitalio", "busio"]

autodoc_mock_imports = ["displayio"]

intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)}

Expand Down
10 changes: 5 additions & 5 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ Table of Contents
.. toctree::
:caption: Tutorials

.. todo:: Add any Learn guide links here. If there are none, then simply delete this todo and leave
the toctree above for use later.

.. toctree::
:caption: Related Products

.. todo:: Add any product links here. If there are none, then simply delete this todo and leave
the toctree above for use later.
1.8" SPI TFT display, 160x128 18-bit color <https://www.adafruit.com/product/618>
Adafruit 0.96" 160x80 Color TFT Display w/ MicroSD Card Breakout <https://www.adafruit.com/product/3533>
1.8" Color TFT LCD display with MicroSD Card Breakout <https://www.adafruit.com/product/358>
Adafruit 1.44" Color TFT LCD Display with MicroSD Card breakout <https://www.adafruit.com/product/2088>
Adafruit Mini Color TFT with Joystick FeatherWing <https://www.adafruit.com/product/3321>

.. toctree::
:caption: Other Links
Expand Down
38 changes: 38 additions & 0 deletions examples/st7735_128x160_simpletest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
This test will initialize the display using displayio
and draw a solid red background
"""

import board
import displayio
from adafruit_st7735.st7735r import ST7735R

spi = board.SPI()
tft_cs = board.D5
tft_dc = board.D6

displayio.release_displays()
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=board.D9)

display = ST7735R(display_bus, width=128, height=160, init=b"\x36\x01\xC0")

# Make the display context
splash = displayio.Group(max_size=10)
display.show(splash)

color_bitmap = displayio.Bitmap(128, 160, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFF0000

try:
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
position=(0, 0))
except TypeError:
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)

while True:
pass
43 changes: 43 additions & 0 deletions examples/st7735_miniTFT_simpletest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
This example will test out the display on the Mini TFT FeatherWing
"""
import board
import displayio
from adafruit_seesaw.seesaw import Seesaw
from adafruit_st7735.st7735r import ST7735R

reset_pin = 8
i2c = board.I2C()
ss = Seesaw(i2c, 0x5E)
ss.pin_mode(reset_pin, ss.OUTPUT)

spi = board.SPI()
tft_cs = board.D5
tft_dc = board.D6

displayio.release_displays()
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=board.D9)

ss.digital_write(reset_pin, True)
display = ST7735R(display_bus, width=160, height=80, rowstart=24, init=b"\x36\x01\x60")

# Make the display context
splash = displayio.Group(max_size=10)
display.show(splash)

color_bitmap = displayio.Bitmap(160, 80, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFF0000

try:
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
position=(0, 0))
except TypeError:
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)

while True:
pass
45 changes: 31 additions & 14 deletions examples/st7735_simpletest.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import adafruit_st7735
"""
This test will initialize the display using displayio
and draw a solid red background
"""

import board
import busio
import displayio
import time
from adafruit_st7735.st7735r import ST7735R

spi = board.SPI()
tft_cs = board.D5
tft_dc = board.D6

displayio.release_displays()
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=board.D9)

display = ST7735R(display_bus, width=128, height=128, colstart=2, rowstart=1)

# Make the display context
splash = displayio.Group(max_size=10)
display.show(splash)

spi = busio.SPI(board.SCL, board.SDA)
bus = displayio.FourWire(spi, chip_select=board.D9, command=board.D7, reset=board.D8)
display = adafruit_st7735.ST7735(bus, width=128, height=128)
color_bitmap = displayio.Bitmap(128, 128, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0xFF0000

s = displayio.Shape(10, 10)
p = displayio.Palette(2)
p[1] = 0xff0000
s = displayio.Sprite(s, pixel_shader=p, position=(0,0))
everything = displayio.Group(max_size=10)
everything.append(s)
display.show(everything)
try:
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
position=(0, 0))
except TypeError:
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)

time.sleep(10)
while True:
pass