Skip to content

Commit 1361b03

Browse files
committed
feat: add madctl param for rotation and BGR/RGB
1 parent 230cff0 commit 1361b03

File tree

6 files changed

+125
-7
lines changed

6 files changed

+125
-7
lines changed

25.2

Whitespace-only changes.

README.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@ Usage Example
6464
while True:
6565
pass
6666
67+
Custom MADCTL Example
68+
---------------------
69+
70+
You can now override the **MADCTL register** to apply hardware-level rotations or control BGR/RGB order directly.
71+
This can improve performance when using `OnDiskBitmap` or other rotation-sensitive cases.
72+
73+
.. code-block:: python
74+
75+
import board
76+
import displayio
77+
import fourwire
78+
import adafruit_ili9341
79+
80+
spi = board.SPI()
81+
tft_cs = board.D9
82+
tft_dc = board.D10
83+
84+
displayio.release_displays()
85+
display_bus = fourwire.FourWire(spi, command=tft_dc, chip_select=tft_cs)
86+
87+
# Pass a custom MADCTL value (example: 0b01011000)
88+
display = adafruit_ili9341.ILI9341(display_bus, width=320, height=240, madctl=0b01011000)
89+
6790
Documentation
6891
=============
6992

adafruit_ili9341.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,48 @@ class ILI9341(BusDisplay):
9292
ILI9341 display driver
9393
9494
:param FourWire bus: bus that the display is connected to
95+
:param bool bgr: Use BGR color order instead of RGB
96+
:param bool invert: Invert the display
97+
:param int madctl: Optional custom MADCTL value to override rotation/scan order bits
9598
"""
9699

97-
def __init__(self, bus: FourWire, *, bgr: bool = False, invert: bool = False, **kwargs: Any):
98-
init_sequence = _INIT_SEQUENCE
99-
if bgr:
100-
init_sequence += b"\x36\x01\x30" # _MADCTL Default rotation plus BGR encoding
101-
else:
102-
init_sequence += b"\x36\x01\x38" # _MADCTL Default rotation plus RGB encoding
100+
def __init__(
101+
self,
102+
bus: FourWire,
103+
*,
104+
bgr: bool = False,
105+
invert: bool = False,
106+
madctl: int | None = None,
107+
**kwargs: Any,
108+
):
109+
# Start with base init sequence
110+
init_sequence = bytearray(_INIT_SEQUENCE)
111+
112+
# --- Replace existing MADCTL instead of appending ---
113+
# Find MADCTL (0x36) in init sequence
114+
try:
115+
idx = init_sequence.index(0x36)
116+
# Overwrite the length (always 1) + value
117+
if madctl is not None:
118+
init_sequence[idx + 1] = 0x01
119+
init_sequence[idx + 2] = madctl
120+
elif bgr:
121+
init_sequence[idx + 1] = 0x01
122+
init_sequence[idx + 2] = 0x30 # BGR encoding
123+
else:
124+
init_sequence[idx + 1] = 0x01
125+
init_sequence[idx + 2] = 0x38 # RGB encoding
126+
except ValueError:
127+
# If no MADCTL present, append it
128+
if madctl is not None:
129+
init_sequence += bytes([0x36, 0x01, madctl])
130+
elif bgr:
131+
init_sequence += b"\x36\x01\x30"
132+
else:
133+
init_sequence += b"\x36\x01\x38"
134+
135+
# Inversion
103136
if invert:
104-
init_sequence += b"\x21\x00" # _INVON
137+
init_sequence += b"\x21\x00"
105138

106139
super().__init__(bus, init_sequence, **kwargs)

pyproject.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,16 @@ py-modules = ["adafruit_ili9341"]
4646
[tool.setuptools.dynamic]
4747
dependencies = {file = ["requirements.txt"]}
4848
optional-dependencies = {optional = {file = ["optional_requirements.txt"]}}
49+
50+
[tool.ruff]
51+
# Enable default linting rules
52+
select = ["E", "F"]
53+
54+
# Ignore specific rules if needed
55+
ignore = []
56+
57+
# Allow fixing issues automatically with `ruff check --fix`
58+
fix = true
59+
60+
# Formatting (instead of Black)
61+
line-length = 88

python

Whitespace-only changes.

test_madctl.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# SPDX-FileCopyrightText: 2025 Ritesh
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
import pytest
6+
7+
from adafruit_ili9341 import ILI9341
8+
9+
10+
class DummyBus:
11+
"""A fake bus to avoid hardware dependency."""
12+
13+
def __init__(self):
14+
self.commands = []
15+
16+
def send(self, *args, **kwargs):
17+
self.commands.append((args, kwargs))
18+
19+
20+
def extract_madctl_bytes(init_seq: bytes) -> bytes | None:
21+
"""
22+
Helper to find MADCTL command (0x36) in the init sequence.
23+
Returns 2 bytes: [0x36, value] or None if not present.
24+
"""
25+
for i in range(len(init_seq) - 2):
26+
if init_seq[i] == 0x36:
27+
return init_seq[i : i + 3]
28+
return None
29+
30+
31+
def test_default_rgb_encoding():
32+
bus = DummyBus()
33+
disp = ILI9341(bus)
34+
madctl = extract_madctl_bytes(disp.init_sequence)
35+
assert madctl == b"\x36\x01\x38" # Default RGB
36+
37+
38+
def test_bgr_encoding():
39+
bus = DummyBus()
40+
disp = ILI9341(bus, bgr=True)
41+
madctl = extract_madctl_bytes(disp.init_sequence)
42+
assert madctl == b"\x36\x01\x30" # BGR mode
43+
44+
45+
def test_custom_madctl():
46+
bus = DummyBus()
47+
disp = ILI9341(bus, madctl=0b01011000)
48+
madctl = extract_madctl_bytes(disp.init_sequence)
49+
assert madctl == bytes([0x36, 0x01, 0b01011000]) # Custom override

0 commit comments

Comments
 (0)