Skip to content

Commit ac0e09c

Browse files
committed
Further improve documentation
Improve primitives.md and also introduce a new documentation page for displays and their drivers.
2 parents 2974f26 + 32c27f3 commit ac0e09c

File tree

3 files changed

+349
-5
lines changed

3 files changed

+349
-5
lines changed

README.Md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ software dithering
8989

9090
[SDL Linux display](sdl_display/) is also supported and can be built as an AtomVM plugin.
9191

92+
See also [display drivers](docs/display-drivers.md) documentation page for additional information.
93+
9294
## Platform Support
9395

9496
AtomGL is currently compatible with **ESP32** microcontrollers. Linux with SDL is also supported for

docs/display-drivers.md

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
# Display Drivers
2+
3+
This document describes how to configure and use the various display drivers supported by AtomGL.
4+
5+
## Overview
6+
7+
To use a display with AtomGL, you need:
8+
1. A communication interface (either SPI or I²C) that must be opened and configured
9+
2. A display driver selected by providing a `compatible` string that matches your display model
10+
11+
The display driver will handle all the low-level communication and rendering, while you provide
12+
display lists describing what should be shown.
13+
14+
## Using SPI Displays
15+
16+
Most displays use SPI for communication. First, configure and open an SPI host, then pass it to the
17+
display driver.
18+
19+
### Basic SPI Setup
20+
21+
```elixir
22+
# Configure SPI bus
23+
spi_opts = %{
24+
bus_config: %{
25+
sclk: 35, # Serial clock pin
26+
mosi: 34, # Master Out Slave In pin
27+
miso: 33, # Master In Slave Out pin (optional for displays)
28+
peripheral: "spi2"
29+
},
30+
device_config: %{
31+
# Device-specific configuration
32+
}
33+
}
34+
35+
# Open SPI host
36+
spi_host = :spi.open(spi_opts)
37+
38+
# Configure display
39+
display_opts = [
40+
spi_host: spi_host,
41+
width: 320,
42+
height: 240,
43+
compatible: "ilitek,ili9341",
44+
cs: 22, # Chip select pin
45+
dc: 21, # Data/Command pin
46+
reset: 18, # Reset pin
47+
# Additional options...
48+
]
49+
50+
# Open display port
51+
display = :erlang.open_port({:spawn, "display"}, display_opts)
52+
```
53+
54+
## Using I²C Displays
55+
56+
Some displays (like small OLED screens) use I²C communication.
57+
58+
### Basic I²C Setup
59+
60+
```elixir
61+
# Configure I²C bus
62+
i2c_opts = [
63+
sda: 8, # Data pin
64+
scl: 9, # Clock pin
65+
clock_speed_hz: 1_000_000,
66+
peripheral: "i2c0"
67+
]
68+
69+
# Open I²C host
70+
i2c_host = :i2c.open(i2c_opts)
71+
72+
# Configure display
73+
display_opts = [
74+
i2c_host: i2c_host,
75+
width: 128,
76+
height: 64,
77+
compatible: "solomon-systech,ssd1306",
78+
invert: true
79+
]
80+
81+
# Open display port
82+
display = :erlang.open_port({:spawn, "display"}, display_opts)
83+
```
84+
85+
## Common Display Options
86+
87+
### Backlight Configuration
88+
89+
Many displays support backlight control:
90+
91+
```elixir
92+
backlight_opts = [
93+
backlight: 5, # Backlight GPIO pin
94+
backlight_active: :low, # :low or :high
95+
backlight_enabled: true # Enable on startup
96+
]
97+
```
98+
99+
## Supported Displays
100+
101+
### ILI9341 / ILI9342C (ilitek,ili9341 / ilitek,ili9342c)
102+
103+
240×320 TFT display with 16-bit colors. Both variants use the same driver.
104+
105+
**Compatible strings:** `"ilitek,ili9341"` or `"ilitek,ili9342c"`
106+
107+
| Option | Type | Description | Default |
108+
|--------|------|-------------|---------|
109+
| `spi_host` | term | SPI host reference | Required |
110+
| `width` | integer | Display width in pixels | 320 |
111+
| `height` | integer | Display height in pixels | 240 |
112+
| `cs` | integer | Chip select GPIO pin | Required |
113+
| `dc` | integer | Data/Command GPIO pin | Required |
114+
| `reset` | integer | Reset GPIO pin | Required |
115+
| `rotation` | integer | Display rotation (0-3) | 0 |
116+
| `enable_tft_invon` | boolean | Enable color inversion | false |
117+
| `backlight` | integer | Backlight GPIO pin | Optional |
118+
| `backlight_active` | atom | Backlight active level (:low/:high) | Optional |
119+
| `backlight_enabled` | boolean | Enable backlight on init | Optional |
120+
121+
**Example:**
122+
```elixir
123+
ili9341_opts = [
124+
spi_host: spi_host,
125+
compatible: "ilitek,ili9341",
126+
width: 320,
127+
height: 240,
128+
cs: 22,
129+
dc: 21,
130+
reset: 18,
131+
rotation: 1,
132+
backlight: 5,
133+
backlight_active: :low,
134+
backlight_enabled: true,
135+
enable_tft_invon: false
136+
]
137+
```
138+
139+
### ST7789 / ST7796 (sitronix,st7789 / sitronix,st7796)
140+
141+
TFT displays with 16-bit colors.
142+
143+
**Compatible strings:** `"sitronix,st7789"` or `"sitronix,st7796"`
144+
145+
| Option | Type | Description | Default |
146+
|--------|------|-------------|---------|
147+
| `spi_host` | term | SPI host reference | Required |
148+
| `width` | integer | Display width in pixels | 320 |
149+
| `height` | integer | Display height in pixels | 240 |
150+
| `cs` | integer | Chip select GPIO pin | Required |
151+
| `dc` | integer | Data/Command GPIO pin | Required |
152+
| `reset` | integer | Reset GPIO pin | Optional |
153+
| `rotation` | integer | Display rotation (0-3) | 0 |
154+
| `x_offset` | integer | X-axis offset in pixels | 0 |
155+
| `y_offset` | integer | Y-axis offset in pixels | 0 |
156+
| `enable_tft_invon` | boolean | Enable color inversion | false |
157+
| `init_list` | list | Custom initialization sequence | Optional |
158+
| `backlight` | integer | Backlight GPIO pin | Optional |
159+
| `backlight_active` | atom | Backlight active level (:low/:high) | Optional |
160+
| `backlight_enabled` | boolean | Enable backlight on init | Optional |
161+
162+
**Example with custom initialization:**
163+
```elixir
164+
st7796_opts = [
165+
spi_host: spi_host,
166+
compatible: "sitronix,st7796",
167+
width: 480,
168+
height: 222,
169+
y_offset: 49,
170+
cs: 38,
171+
dc: 37,
172+
init_list: [
173+
{0x01, <<0x00>>}, # {command, <<data>>}
174+
{:sleep_ms, 120} # wait 120 ms
175+
# ...
176+
]
177+
]
178+
```
179+
180+
### SSD1306 / SH1106 (solomon-systech,ssd1306 / sino-wealth,sh1106)
181+
182+
128×64 monochrome OLED displays using I²C communication.
183+
184+
**Compatible strings:** `"solomon-systech,ssd1306"` or `"sino-wealth,sh1106"`
185+
186+
| Option | Type | Description | Default |
187+
|--------|------|-------------|---------|
188+
| `i2c_host` | term | I²C host reference | Required |
189+
| `width` | integer | Display width in pixels | 128 |
190+
| `height` | integer | Display height in pixels | 64 |
191+
| `reset` | integer | Reset GPIO pin | Optional |
192+
| `invert` | boolean | Invert display colors | false |
193+
194+
**Example:**
195+
```elixir
196+
ssd1306_opts = [
197+
i2c_host: i2c_host,
198+
compatible: "solomon-systech,ssd1306",
199+
width: 128,
200+
height: 64,
201+
invert: false,
202+
reset: 16 # Optional
203+
]
204+
```
205+
206+
### Sharp Memory LCD (sharp,memory-lcd)
207+
208+
400×240 monochrome memory LCD with ultra-low power consumption.
209+
210+
**Compatible string:** `"sharp,memory-lcd"`
211+
212+
| Option | Type | Description | Default |
213+
|--------|------|-------------|---------|
214+
| `spi_host` | term | SPI host reference | Required |
215+
| `width` | integer | Display width in pixels | 400 |
216+
| `height` | integer | Display height in pixels | 240 |
217+
| `cs` | integer | Chip select GPIO pin | Required |
218+
| `en` | integer | Enable GPIO pin | Optional |
219+
220+
**Example:**
221+
```elixir
222+
sharp_lcd_opts = [
223+
spi_host: spi_host,
224+
compatible: "sharp,memory-lcd",
225+
cs: 22,
226+
en: 23 # Optional enable pin
227+
]
228+
```
229+
230+
### Waveshare 5.65" ACeP 7-Color (waveshare,5in65-acep-7c)
231+
232+
600×480 7-color E-Paper display. Driver has software dithering support.
233+
234+
**Compatible string:** `"waveshare,5in65-acep-7c"`
235+
236+
| Option | Type | Description | Default |
237+
|--------|------|-------------|---------|
238+
| `spi_host` | term | SPI host reference | Required |
239+
| `width` | integer | Display width in pixels | 600 |
240+
| `height` | integer | Display height in pixels | 480 |
241+
| `cs` | integer | Chip select GPIO pin | Required |
242+
| `dc` | integer | Data/Command GPIO pin | Required |
243+
| `reset` | integer | Reset GPIO pin | Required |
244+
| `busy` | integer | Busy signal GPIO pin | Required |
245+
246+
**Note:** E-Paper displays have slow refresh rates due to their technology.
247+
248+
**Example:**
249+
```elixir
250+
epaper_opts = [
251+
spi_host: spi_host,
252+
compatible: "waveshare,5in65-acep-7c",
253+
cs: 22,
254+
dc: 21,
255+
reset: 18,
256+
busy: 19
257+
]
258+
```
259+
260+
## Custom Initialization Sequences
261+
262+
Many displays require specific initialization sequences with carefully tuned values for voltages,
263+
timing, gamma curves, and other display-specific parameters. For displays that need custom
264+
initialization, you can provide an `init_list`:
265+
266+
```elixir
267+
init_list: [
268+
{0x01, <<0x00>>},
269+
{:sleep_ms, 120}
270+
# ...
271+
]
272+
```
273+
274+
Each entry can be:
275+
- `{command, data}` - Send command byte followed by data bytes
276+
- `{:sleep_ms, milliseconds}` - Delay for specified time
277+
278+
These sequences are highly specific to each display model and typically come from the manufacturer's datasheet or reference implementation.
279+
280+
## Updating the Display
281+
282+
Once configured, update the display using the display port:
283+
284+
```elixir
285+
# Create display list
286+
items = [
287+
{:text, 10, 20, :default16px, 0x000000, 0xFFFFFF, "Hello, World!"},
288+
{:rect, 0, 0, 320, 240, 0xFFFFFF} # White background
289+
]
290+
291+
# Send update command
292+
:erlang.port_call(display, {:update, items}, 5000)
293+
```
294+
295+
**Note:** While direct port calls work, the recommended approach is to use [avm_scene](https://github.com/atomvm/avm_scene) which provides a higher-level interface for managing display updates and handling the display list lifecycle properly.
296+
297+
For more information about display primitives and the display list concept, see the [primitives documentation](primitives.md).

0 commit comments

Comments
 (0)