├── .gitignore
├── LICENSE
├── README.md
├── VERSION
├── docs
└── ST7789.jpg
└── st7789
├── micropython.mk
├── st7789.c
└── st7789.h
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | .idea
3 |
4 | *.o
5 | *.P
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Ivan Belokobylskiy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ST7789 Driver for MicroPython
2 | =============================
3 |
4 |
5 | Overview
6 | --------
7 | This is a driver for MicroPython to handle cheap displays
8 | based on ST7789 chip.
9 |
10 |
11 |
12 |
13 |
14 | It supports both 240x240 and 135x240 variants of displays.
15 |
16 | It is written in pure C, so you have to build
17 | firmware by yourself.
18 | ESP8266, ESP32, and STM32 ports are supported for now.
19 |
20 |
21 | Building instruction
22 | ---------------------
23 |
24 | Prepare build tools as described in the manual.
25 | You should follow the instruction for building MicroPython and
26 | ensure that you can build the firmware without this display module.
27 |
28 | Clone this module alongside the MPY sources:
29 |
30 | git clone https://github.com/devbis/st7789_mpy.git
31 |
32 | Go to MicroPython ports directory and for ESP8266 run:
33 |
34 | cd micropython/ports/esp8266
35 |
36 | for ESP32:
37 |
38 | cd micropython/ports/esp32
39 |
40 | And then compile the module with specified USER_C_MODULES dir
41 |
42 | make USER_C_MODULES=../../../st7789_mpy/ all
43 |
44 |
45 | If you have other user modules, copy the st7789_driver/st7789 to
46 | the user modules directory
47 |
48 | Upload the resulting firmware to your MCU as usual with esptool.py
49 | (See
50 | [MicroPython docs](http://docs.micropython.org/en/latest/esp8266/tutorial/intro.html#deploying-the-firmware)
51 | for more info)
52 |
53 | make deploy
54 |
55 | Working examples
56 | ----------------
57 |
58 | This module was tested on ESP32 and ESP8266 MCUs.
59 |
60 | You have to provide `machine.SPI` object and at least two pins for RESET and
61 | DC pins on the screen for the display object.
62 |
63 |
64 | # ESP 8266
65 |
66 | import machine
67 | import st7789
68 | spi = machine.SPI(1, baudrate=40000000, polarity=1)
69 | display = st7789.ST7789(spi, 240, 240, reset=machine.Pin(5, machine.Pin.OUT), dc=machine.Pin(4, machine.Pin.OUT))
70 | display.init()
71 |
72 |
73 | For ESP32 modules you have to provide specific pins for SPI.
74 | Unfortunately, I was unable to run this display on SPI(1) interface.
75 | For machine.SPI(2) == VSPI you have to use
76 |
77 | - CLK: Pin(18)
78 | - MOSI: Pin(23)
79 |
80 | Other SPI pins are not used.
81 |
82 |
83 | # ESP32
84 |
85 | import machine
86 | import st7789
87 | spi = machine.SPI(2, baudrate=40000000, polarity=1, sck=machine.Pin(18), mosi=machine.Pin(23))
88 | display = st7789.ST7789(spi, 240, 240, reset=machine.Pin(4, machine.Pin.OUT), dc=machine.Pin(2, machine.Pin.OUT))
89 | display.init()
90 |
91 |
92 | I couldn't run the display on an SPI with baudrate higher than 40MHZ
93 |
94 | Also, the driver was tested on STM32 board:
95 |
96 |
97 | # STM32
98 |
99 | import machine
100 | import st7789
101 | spi = machine.SPI(2, baudrate=12000000, polarity=1)
102 | display = st7789.ST7789(spi, 135, 240, reset=machine.Pin('B3', machine.Pin.OUT), dc=machine.Pin('B6', machine.Pin.OUT))
103 | display.init()
104 |
105 |
106 | Methods
107 | -------------
108 |
109 | This driver supports only 16bit colors in RGB565 notation.
110 |
111 |
112 | - `ST7789.fill(color)`
113 |
114 | Fill the entire display with the specified color.
115 |
116 | - `ST7789.pixel(x, y, color)`
117 |
118 | Set the specified pixel to the given color.
119 |
120 | - `ST7789.line(x0, y0, x1, y1, color)`
121 |
122 | Draws a single line with the provided `color` from (`x0`, `y0`) to
123 | (`x1`, `y1`).
124 |
125 | - `ST7789.hline(x, y, length, color)`
126 |
127 | Draws a single horizontal line with the provided `color` and `length`
128 | in pixels. Along with `vline`, this is a fast version with reduced
129 | number of SPI calls.
130 |
131 | - `ST7789.vline(x, y, length, color)`
132 |
133 | Draws a single horizontal line with the provided `color` and `length`
134 | in pixels.
135 |
136 | - `ST7789.rect(x, y, width, height, color)`
137 |
138 | Draws a rectangle from (`x`, `y`) with corresponding dimensions
139 |
140 | - `ST7789.fill_rect(x, y, width, height, color)`
141 |
142 | Fill a rectangle starting from (`x`, `y`) coordinates
143 |
144 | - `ST7789.blit_buffer(buffer, x, y, width, height)`
145 |
146 | Copy bytes() or bytearray() content to the screen internal memory.
147 | Note: every color requires 2 bytes in the array
148 |
149 | Also, the module exposes predefined colors:
150 | `BLACK`, `BLUE`, `RED`, `GREEN`, `CYAN`, `MAGENTA`, `YELLOW`, and `WHITE`
151 |
152 |
153 | Helper functions
154 | ----------------
155 |
156 | - `color565(r, g, b)`
157 |
158 | Pack a color into 2-bytes rgb565 format
159 |
160 | - `map_bitarray_to_rgb565(bitarray, buffer, width, color=WHITE, bg_color=BLACK)`
161 |
162 | Convert a bitarray to the rgb565 color buffer which is suitable for blitting.
163 | Bit 1 in bitarray is a pixel with `color` and 0 - with `bg_color`.
164 |
165 | This is a helper with a good performance to print text with a high
166 | resolution font. You can use an awesome tool
167 | https://github.com/peterhinch/micropython-font-to-py
168 | to generate a bitmap fonts from .ttf and use them as a frozen bytecode from
169 | the ROM memory.
170 |
171 | Performance
172 | -----------
173 |
174 | For the comparison I used an excellent library for Arduino
175 | that can handle this screen.
176 |
177 | https://github.com/ananevilya/Arduino-ST7789-Library/
178 |
179 | Also, I used my slow driver for this screen, written in pure python.
180 |
181 | https://github.com/devbis/st7789py_mpy/
182 |
183 | I used these modules to draw a line from 0,0 to 239,239
184 | The table represents the time in milliseconds for each case
185 |
186 | | | Arduino-ST7789 | st7789py_mpy | st7789_mpy |
187 | |---------|----------------|--------------|---------------|
188 | | ESP8266 | 26 | 450 | 12 |
189 | | ESP32 | 23 | 450 | 47 |
190 |
191 |
192 | As you can see, the ESP32 module draws a line 4 times slower than
193 | the older ESP8266 module.
194 |
195 |
196 | Troubleshooting
197 | ---------------
198 |
199 | #### Overflow of iram1_0_seg
200 |
201 | When building a firmware for esp8266 you can see this failure message from
202 | the linker:
203 |
204 | LINK build/firmware.elf
205 | xtensa-lx106-elf-ld: build/firmware.elf section `.text' will not fit in region `iram1_0_seg'
206 | xtensa-lx106-elf-ld: region `iram1_0_seg' overflowed by 292 bytes
207 | Makefile:192: recipe for target 'build/firmware.elf' failed
208 |
209 | To fix this issue, you have to put st7789 module to irom0 section.
210 | Edit `esp8266_common.ld` file in the `ports/esp8266` dir and add a line
211 |
212 | *st7789/*.o(.literal* .text*)
213 |
214 | in the `.irom0.text : ALIGN(4)` section
215 |
216 |
217 | #### Unsupported dimensions
218 |
219 | This driver supports only 240x240 and 135x240 pixel displays.
220 | If you have a display with an unsupported resolution, you can pass
221 | `xstart` and `ystart` parameters to the display constructor to set the
222 | required offsets.
223 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 0.1.5
2 |
--------------------------------------------------------------------------------
/docs/ST7789.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devbis/st7789_mpy/23e6f36acff40df7f1429cf5e0e5541f97c2540b/docs/ST7789.jpg
--------------------------------------------------------------------------------
/st7789/micropython.mk:
--------------------------------------------------------------------------------
1 | ST7789_MOD_DIR := $(USERMOD_DIR)
2 | SRC_USERMOD += $(addprefix $(ST7789_MOD_DIR)/, \
3 | st7789.c \
4 | )
5 | CFLAGS_USERMOD += -I$(ST7789_MOD_DIR) -DMODULE_ST7789_ENABLED=1
6 | # CFLAGS_USERMOD += -DEXPOSE_EXTRA_METHODS=1
7 |
--------------------------------------------------------------------------------
/st7789/st7789.c:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2019 Ivan Belokobylskiy
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | #define __ST7789_VERSION__ "0.1.5"
26 |
27 | #include "py/obj.h"
28 | #include "py/runtime.h"
29 | #include "py/builtin.h"
30 | #include "py/mphal.h"
31 | #include "extmod/machine_spi.h"
32 |
33 | #include "st7789.h"
34 |
35 | // allow compiling against MP <=1.12
36 | #ifndef MP_ERROR_TEXT
37 | #define MP_ERROR_TEXT(a) a
38 | #endif
39 |
40 | #define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
41 | #define ABS(N) (((N)<0)?(-(N)):(N))
42 | #define mp_hal_delay_ms(delay) (mp_hal_delay_us(delay * 1000))
43 |
44 | #define CS_LOW() { if(self->cs) {mp_hal_pin_write(self->cs, 0);} }
45 | #define CS_HIGH() { if(self->cs) {mp_hal_pin_write(self->cs, 1);} }
46 | #define DC_LOW() mp_hal_pin_write(self->dc, 0)
47 | #define DC_HIGH() mp_hal_pin_write(self->dc, 1)
48 | #define RESET_LOW() mp_hal_pin_write(self->reset, 0)
49 | #define RESET_HIGH() mp_hal_pin_write(self->reset, 1)
50 | #define DISP_HIGH() mp_hal_pin_write(self->backlight, 1)
51 | #define DISP_LOW() mp_hal_pin_write(self->backlight, 0)
52 |
53 |
54 | STATIC void write_spi(mp_obj_base_t *spi_obj, const uint8_t *buf, int len) {
55 | mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)spi_obj->type->protocol;
56 | spi_p->transfer(spi_obj, len, buf, NULL);
57 | }
58 |
59 | // this is the actual C-structure for our new object
60 | typedef struct _st7789_ST7789_obj_t {
61 | mp_obj_base_t base;
62 |
63 | mp_obj_base_t *spi_obj;
64 | uint8_t width;
65 | uint8_t height;
66 | uint8_t xstart;
67 | uint8_t ystart;
68 | mp_hal_pin_obj_t reset;
69 | mp_hal_pin_obj_t dc;
70 | mp_hal_pin_obj_t cs;
71 | mp_hal_pin_obj_t backlight;
72 | } st7789_ST7789_obj_t;
73 |
74 |
75 | // just a definition
76 | mp_obj_t st7789_ST7789_make_new( const mp_obj_type_t *type,
77 | size_t n_args,
78 | size_t n_kw,
79 | const mp_obj_t *args );
80 | STATIC void st7789_ST7789_print( const mp_print_t *print,
81 | mp_obj_t self_in,
82 | mp_print_kind_t kind ) {
83 | (void)kind;
84 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
85 | mp_printf(print, "", self->width, self->height, self->spi_obj);
86 | }
87 |
88 | /* methods start */
89 |
90 | STATIC void write_cmd(st7789_ST7789_obj_t *self, uint8_t cmd, const uint8_t *data, int len) {
91 | CS_LOW()
92 | if (cmd) {
93 | DC_LOW();
94 | write_spi(self->spi_obj, &cmd, 1);
95 | }
96 | if (len > 0) {
97 | DC_HIGH();
98 | write_spi(self->spi_obj, data, len);
99 | }
100 | CS_HIGH()
101 | }
102 |
103 | STATIC void set_window(st7789_ST7789_obj_t *self, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
104 | if (x0 > x1 || x1 >= self->width) {
105 | return;
106 | }
107 | if (y0 > y1 || y1 >= self->height) {
108 | return;
109 | }
110 | uint8_t bufx[4] = {(x0+self->xstart) >> 8, (x0+self->xstart) & 0xFF, (x1+self->xstart) >> 8, (x1+self->xstart) & 0xFF};
111 | uint8_t bufy[4] = {(y0+self->ystart) >> 8, (y0+self->ystart) & 0xFF, (y1+self->ystart) >> 8, (y1+self->ystart) & 0xFF};
112 | write_cmd(self, ST7789_CASET, bufx, 4);
113 | write_cmd(self, ST7789_RASET, bufy, 4);
114 | write_cmd(self, ST7789_RAMWR, NULL, 0);
115 | }
116 |
117 | STATIC void fill_color_buffer(mp_obj_base_t* spi_obj, uint16_t color, int length) {
118 | uint8_t hi = color >> 8, lo = color;
119 | const int buffer_pixel_size = 128;
120 | int chunks = length / buffer_pixel_size;
121 | int rest = length % buffer_pixel_size;
122 |
123 | uint8_t buffer[buffer_pixel_size * 2]; // 128 pixels
124 | // fill buffer with color data
125 | for (int i = 0; i < length && i < buffer_pixel_size; i++) {
126 | buffer[i*2] = hi;
127 | buffer[i*2 + 1] = lo;
128 | }
129 |
130 | if (chunks) {
131 | for (int j = 0; j < chunks; j ++) {
132 | write_spi(spi_obj, buffer, buffer_pixel_size*2);
133 | }
134 | }
135 | if (rest) {
136 | write_spi(spi_obj, buffer, rest*2);
137 | }
138 | }
139 |
140 |
141 | STATIC void draw_pixel(st7789_ST7789_obj_t *self, uint8_t x, uint8_t y, uint16_t color) {
142 | uint8_t hi = color >> 8, lo = color;
143 | set_window(self, x, y, x, y);
144 | DC_HIGH();
145 | CS_LOW();
146 | write_spi(self->spi_obj, &hi, 1);
147 | write_spi(self->spi_obj, &lo, 1);
148 | CS_HIGH();
149 | }
150 |
151 |
152 | STATIC void fast_hline(st7789_ST7789_obj_t *self, uint8_t x, uint8_t y, uint16_t w, uint16_t color) {
153 | set_window(self, x, y, x + w - 1, y);
154 | DC_HIGH();
155 | CS_LOW();
156 | fill_color_buffer(self->spi_obj, color, w);
157 | CS_HIGH();
158 | }
159 |
160 |
161 | STATIC void fast_vline(st7789_ST7789_obj_t *self, uint8_t x, uint8_t y, uint16_t w, uint16_t color) {
162 | set_window(self, x, y, x, y + w - 1);
163 | DC_HIGH();
164 | CS_LOW();
165 | fill_color_buffer(self->spi_obj, color, w);
166 | CS_HIGH();
167 | }
168 |
169 |
170 | STATIC mp_obj_t st7789_ST7789_hard_reset(mp_obj_t self_in) {
171 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
172 |
173 | CS_LOW();
174 | RESET_HIGH();
175 | mp_hal_delay_ms(50);
176 | RESET_LOW();
177 | mp_hal_delay_ms(50);
178 | RESET_HIGH();
179 | mp_hal_delay_ms(150);
180 | CS_HIGH();
181 | return mp_const_none;
182 | }
183 |
184 | STATIC mp_obj_t st7789_ST7789_soft_reset(mp_obj_t self_in) {
185 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
186 |
187 | write_cmd(self, ST7789_SWRESET, NULL, 0);
188 | mp_hal_delay_ms(150);
189 | return mp_const_none;
190 | }
191 |
192 | // do not expose extra method to reduce size
193 | #ifdef EXPOSE_EXTRA_METHODS
194 | STATIC mp_obj_t st7789_ST7789_write(mp_obj_t self_in, mp_obj_t command, mp_obj_t data) {
195 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
196 |
197 | mp_buffer_info_t src;
198 | if (data == mp_const_none) {
199 | write_cmd(self, (uint8_t)mp_obj_get_int(command), NULL, 0);
200 | } else {
201 | mp_get_buffer_raise(data, &src, MP_BUFFER_READ);
202 | write_cmd(self, (uint8_t)mp_obj_get_int(command), (const uint8_t*)src.buf, src.len);
203 | }
204 |
205 | return mp_const_none;
206 | }
207 | MP_DEFINE_CONST_FUN_OBJ_3(st7789_ST7789_write_obj, st7789_ST7789_write);
208 |
209 | MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_hard_reset_obj, st7789_ST7789_hard_reset);
210 | MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_soft_reset_obj, st7789_ST7789_soft_reset);
211 |
212 | STATIC mp_obj_t st7789_ST7789_sleep_mode(mp_obj_t self_in, mp_obj_t value) {
213 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
214 | if(mp_obj_is_true(value)) {
215 | write_cmd(self, ST7789_SLPIN, NULL, 0);
216 | } else {
217 | write_cmd(self, ST7789_SLPOUT, NULL, 0);
218 | }
219 | return mp_const_none;
220 | }
221 | MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_sleep_mode_obj, st7789_ST7789_sleep_mode);
222 |
223 | STATIC mp_obj_t st7789_ST7789_set_window(size_t n_args, const mp_obj_t *args) {
224 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
225 | mp_int_t x0 = mp_obj_get_int(args[1]);
226 | mp_int_t x1 = mp_obj_get_int(args[2]);
227 | mp_int_t y0 = mp_obj_get_int(args[3]);
228 | mp_int_t y1 = mp_obj_get_int(args[4]);
229 |
230 | set_window(self, x0, y0, x1, y1);
231 | return mp_const_none;
232 | }
233 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_set_window_obj, 5, 5, st7789_ST7789_set_window);
234 |
235 | #endif
236 |
237 | STATIC mp_obj_t st7789_ST7789_inversion_mode(mp_obj_t self_in, mp_obj_t value) {
238 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
239 | if(mp_obj_is_true(value)) {
240 | write_cmd(self, ST7789_INVON, NULL, 0);
241 | } else {
242 | write_cmd(self, ST7789_INVOFF, NULL, 0);
243 | }
244 | return mp_const_none;
245 | }
246 | MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_inversion_mode_obj, st7789_ST7789_inversion_mode);
247 |
248 |
249 | STATIC mp_obj_t st7789_ST7789_fill_rect(size_t n_args, const mp_obj_t *args) {
250 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
251 | mp_int_t x = mp_obj_get_int(args[1]);
252 | mp_int_t y = mp_obj_get_int(args[2]);
253 | mp_int_t w = mp_obj_get_int(args[3]);
254 | mp_int_t h = mp_obj_get_int(args[4]);
255 | mp_int_t color = mp_obj_get_int(args[5]);
256 |
257 | set_window(self, x, y, x + w - 1, y + h - 1);
258 | DC_HIGH();
259 | CS_LOW();
260 | fill_color_buffer(self->spi_obj, color, w * h);
261 | CS_HIGH();
262 |
263 | return mp_const_none;
264 | }
265 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_fill_rect_obj, 6, 6, st7789_ST7789_fill_rect);
266 |
267 |
268 | STATIC mp_obj_t st7789_ST7789_fill(mp_obj_t self_in, mp_obj_t _color) {
269 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
270 | mp_int_t color = mp_obj_get_int(_color);
271 |
272 | set_window(self, 0, 0, self->width - 1, self->height - 1);
273 | DC_HIGH();
274 | CS_LOW();
275 | fill_color_buffer(self->spi_obj, color, self->width * self->height);
276 | CS_HIGH();
277 |
278 | return mp_const_none;
279 | }
280 | STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_fill_obj, st7789_ST7789_fill);
281 |
282 |
283 | STATIC mp_obj_t st7789_ST7789_pixel(size_t n_args, const mp_obj_t *args) {
284 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
285 | mp_int_t x = mp_obj_get_int(args[1]);
286 | mp_int_t y = mp_obj_get_int(args[2]);
287 | mp_int_t color = mp_obj_get_int(args[3]);
288 |
289 | draw_pixel(self, x, y, color);
290 |
291 | return mp_const_none;
292 | }
293 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_pixel_obj, 4, 4, st7789_ST7789_pixel);
294 |
295 |
296 | STATIC mp_obj_t st7789_ST7789_line(size_t n_args, const mp_obj_t *args) {
297 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
298 | mp_int_t x0 = mp_obj_get_int(args[1]);
299 | mp_int_t y0 = mp_obj_get_int(args[2]);
300 | mp_int_t x1 = mp_obj_get_int(args[3]);
301 | mp_int_t y1 = mp_obj_get_int(args[4]);
302 | mp_int_t color = mp_obj_get_int(args[5]);
303 |
304 | bool steep = ABS(y1 - y0) > ABS(x1 - x0);
305 | if (steep) {
306 | _swap_int16_t(x0, y0);
307 | _swap_int16_t(x1, y1);
308 | }
309 |
310 | if (x0 > x1) {
311 | _swap_int16_t(x0, x1);
312 | _swap_int16_t(y0, y1);
313 | }
314 |
315 | int16_t dx = x1 - x0, dy = ABS(y1 - y0);
316 | int16_t err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
317 |
318 | if (y0 < y1) ystep = 1;
319 |
320 | // Split into steep and not steep for FastH/V separation
321 | if (steep) {
322 | for (; x0 <= x1; x0++) {
323 | dlen++;
324 | err -= dy;
325 | if (err < 0) {
326 | err += dx;
327 | if (dlen == 1) draw_pixel(self, y0, xs, color);
328 | else fast_vline(self, y0, xs, dlen, color);
329 | dlen = 0; y0 += ystep; xs = x0 + 1;
330 | }
331 | }
332 | if (dlen) fast_vline(self, y0, xs, dlen, color);
333 | }
334 | else
335 | {
336 | for (; x0 <= x1; x0++) {
337 | dlen++;
338 | err -= dy;
339 | if (err < 0) {
340 | err += dx;
341 | if (dlen == 1) draw_pixel(self, xs, y0, color);
342 | else fast_hline(self, xs, y0, dlen, color);
343 | dlen = 0; y0 += ystep; xs = x0 + 1;
344 | }
345 | }
346 | if (dlen) fast_hline(self, xs, y0, dlen, color);
347 | }
348 | return mp_const_none;
349 | }
350 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_line_obj, 6, 6, st7789_ST7789_line);
351 |
352 |
353 | STATIC mp_obj_t st7789_ST7789_blit_buffer(size_t n_args, const mp_obj_t *args) {
354 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
355 | mp_buffer_info_t buf_info;
356 | mp_get_buffer_raise(args[1], &buf_info, MP_BUFFER_READ);
357 | mp_int_t x = mp_obj_get_int(args[2]);
358 | mp_int_t y = mp_obj_get_int(args[3]);
359 | mp_int_t w = mp_obj_get_int(args[4]);
360 | mp_int_t h = mp_obj_get_int(args[5]);
361 |
362 | set_window(self, x, y, x + w - 1, y + h - 1);
363 | DC_HIGH();
364 | CS_LOW();
365 |
366 | const int buf_size = 256;
367 | int limit = MIN(buf_info.len, w * h * 2);
368 | int chunks = limit / buf_size;
369 | int rest = limit % buf_size;
370 | int i = 0;
371 | for (; i < chunks; i ++) {
372 | write_spi(self->spi_obj, (const uint8_t*)buf_info.buf + i*buf_size, buf_size);
373 | }
374 | if (rest) {
375 | write_spi(self->spi_obj, (const uint8_t*)buf_info.buf + i*buf_size, rest);
376 | }
377 | CS_HIGH();
378 |
379 | return mp_const_none;
380 | }
381 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_blit_buffer_obj, 6, 6, st7789_ST7789_blit_buffer);
382 |
383 |
384 | STATIC mp_obj_t st7789_ST7789_init(mp_obj_t self_in) {
385 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
386 | st7789_ST7789_hard_reset(self_in);
387 | st7789_ST7789_soft_reset(self_in);
388 | write_cmd(self, ST7789_SLPOUT, NULL, 0);
389 |
390 | const uint8_t color_mode[] = { COLOR_MODE_65K | COLOR_MODE_16BIT};
391 | write_cmd(self, ST7789_COLMOD, color_mode, 1);
392 | mp_hal_delay_ms(10);
393 | const uint8_t madctl[] = { ST7789_MADCTL_ML | ST7789_MADCTL_RGB };
394 | write_cmd(self, ST7789_MADCTL, madctl, 1);
395 |
396 | write_cmd(self, ST7789_INVON, NULL, 0);
397 | mp_hal_delay_ms(10);
398 | write_cmd(self, ST7789_NORON, NULL, 0);
399 | mp_hal_delay_ms(10);
400 |
401 | const mp_obj_t args[] = {
402 | self_in,
403 | mp_obj_new_int(0),
404 | mp_obj_new_int(0),
405 | mp_obj_new_int(self->width),
406 | mp_obj_new_int(self->height),
407 | mp_obj_new_int(BLACK)
408 | };
409 | st7789_ST7789_fill_rect(6, args);
410 | write_cmd(self, ST7789_DISPON, NULL, 0);
411 | mp_hal_delay_ms(100);
412 |
413 | return mp_const_none;
414 | }
415 | MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_init_obj, st7789_ST7789_init);
416 |
417 | STATIC mp_obj_t st7789_ST7789_on(mp_obj_t self_in) {
418 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
419 | DISP_HIGH();
420 | mp_hal_delay_ms(10);
421 |
422 | return mp_const_none;
423 | }
424 | MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_on_obj, st7789_ST7789_on);
425 |
426 | STATIC mp_obj_t st7789_ST7789_off(mp_obj_t self_in) {
427 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
428 | DISP_LOW();
429 | mp_hal_delay_ms(10);
430 |
431 | return mp_const_none;
432 | }
433 | MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_off_obj, st7789_ST7789_off);
434 |
435 | STATIC mp_obj_t st7789_ST7789_hline(size_t n_args, const mp_obj_t *args) {
436 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
437 | mp_int_t x = mp_obj_get_int(args[1]);
438 | mp_int_t y = mp_obj_get_int(args[2]);
439 | mp_int_t w = mp_obj_get_int(args[3]);
440 | mp_int_t color = mp_obj_get_int(args[4]);
441 |
442 | fast_hline(self, x, y, w, color);
443 |
444 | return mp_const_none;
445 | }
446 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_hline_obj, 5, 5, st7789_ST7789_hline);
447 |
448 |
449 | STATIC mp_obj_t st7789_ST7789_vline(size_t n_args, const mp_obj_t *args) {
450 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
451 | mp_int_t x = mp_obj_get_int(args[1]);
452 | mp_int_t y = mp_obj_get_int(args[2]);
453 | mp_int_t w = mp_obj_get_int(args[3]);
454 | mp_int_t color = mp_obj_get_int(args[4]);
455 |
456 | fast_vline(self, x, y, w, color);
457 |
458 | return mp_const_none;
459 | }
460 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_vline_obj, 5, 5, st7789_ST7789_vline);
461 |
462 |
463 | STATIC mp_obj_t st7789_ST7789_rect(size_t n_args, const mp_obj_t *args) {
464 | st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
465 | mp_int_t x = mp_obj_get_int(args[1]);
466 | mp_int_t y = mp_obj_get_int(args[2]);
467 | mp_int_t w = mp_obj_get_int(args[3]);
468 | mp_int_t h = mp_obj_get_int(args[4]);
469 | mp_int_t color = mp_obj_get_int(args[5]);
470 |
471 | fast_hline(self, x, y, w, color);
472 | fast_vline(self, x, y, h, color);
473 | fast_hline(self, x, y + h - 1, w, color);
474 | fast_vline(self, x + w - 1, y, h, color);
475 | return mp_const_none;
476 | }
477 | STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_rect_obj, 6, 6, st7789_ST7789_rect);
478 |
479 |
480 | STATIC const mp_rom_map_elem_t st7789_ST7789_locals_dict_table[] = {
481 | // Do not expose internal functions to fit iram_0 section
482 | #ifdef EXPOSE_EXTRA_METHODS
483 | { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&st7789_ST7789_write_obj) },
484 | { MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&st7789_ST7789_hard_reset_obj) },
485 | { MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&st7789_ST7789_soft_reset_obj) },
486 | { MP_ROM_QSTR(MP_QSTR_sleep_mode), MP_ROM_PTR(&st7789_ST7789_sleep_mode_obj) },
487 | { MP_ROM_QSTR(MP_QSTR_inversion_mode), MP_ROM_PTR(&st7789_ST7789_inversion_mode_obj) },
488 | { MP_ROM_QSTR(MP_QSTR_set_window), MP_ROM_PTR(&st7789_ST7789_set_window_obj) },
489 | #endif
490 | { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&st7789_ST7789_init_obj) },
491 | { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&st7789_ST7789_on_obj) },
492 | { MP_ROM_QSTR(MP_QSTR_off), MP_ROM_PTR(&st7789_ST7789_off_obj) },
493 | { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&st7789_ST7789_pixel_obj) },
494 | { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&st7789_ST7789_line_obj) },
495 | { MP_ROM_QSTR(MP_QSTR_blit_buffer), MP_ROM_PTR(&st7789_ST7789_blit_buffer_obj) },
496 | { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&st7789_ST7789_fill_rect_obj) },
497 | { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&st7789_ST7789_fill_obj) },
498 | { MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&st7789_ST7789_hline_obj) },
499 | { MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&st7789_ST7789_vline_obj) },
500 | { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&st7789_ST7789_rect_obj) },
501 | };
502 |
503 | STATIC MP_DEFINE_CONST_DICT(st7789_ST7789_locals_dict, st7789_ST7789_locals_dict_table);
504 | /* methods end */
505 |
506 |
507 | const mp_obj_type_t st7789_ST7789_type = {
508 | { &mp_type_type },
509 | .name = MP_QSTR_ST7789,
510 | .print = st7789_ST7789_print,
511 | .make_new = st7789_ST7789_make_new,
512 | .locals_dict = (mp_obj_dict_t*)&st7789_ST7789_locals_dict,
513 | };
514 |
515 | mp_obj_t st7789_ST7789_make_new(const mp_obj_type_t *type,
516 | size_t n_args,
517 | size_t n_kw,
518 | const mp_obj_t *all_args ) {
519 | enum {
520 | ARG_spi, ARG_width, ARG_height, ARG_reset, ARG_dc, ARG_cs,
521 | ARG_backlight, ARG_xstart, ARG_ystart
522 | };
523 | static const mp_arg_t allowed_args[] = {
524 | { MP_QSTR_spi, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
525 | { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
526 | { MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
527 | { MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
528 | { MP_QSTR_dc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
529 | { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
530 | { MP_QSTR_backlight, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
531 | { MP_QSTR_xstart, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
532 | { MP_QSTR_ystart, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1} },
533 | };
534 | mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
535 | mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
536 |
537 | // create new object
538 | st7789_ST7789_obj_t *self = m_new_obj(st7789_ST7789_obj_t);
539 | self->base.type = &st7789_ST7789_type;
540 |
541 | // set parameters
542 | mp_obj_base_t *spi_obj = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[ARG_spi].u_obj);
543 | self->spi_obj = spi_obj;
544 | self->width = args[ARG_width].u_int;
545 | self->height = args[ARG_height].u_int;
546 |
547 | if (args[ARG_xstart].u_int >= 0 && args[ARG_ystart].u_int >= 0) {
548 | self->xstart = args[ARG_xstart].u_int;
549 | self->ystart = args[ARG_ystart].u_int;
550 | } else if (self->width == 240 && self->height == 240) {
551 | self->xstart = ST7789_240x240_XSTART;
552 | self->ystart = ST7789_240x240_YSTART;
553 | } else if (self->width == 135 && self->height == 240) {
554 | self->xstart = ST7789_135x240_XSTART;
555 | self->ystart = ST7789_135x240_YSTART;
556 | } else {
557 | mp_raise_ValueError(MP_ERROR_TEXT("Unsupported display. Only 240x240 and 135x240 are supported without xstart and ystart provided"));
558 | }
559 |
560 | if (args[ARG_reset].u_obj == MP_OBJ_NULL
561 | || args[ARG_dc].u_obj == MP_OBJ_NULL) {
562 | mp_raise_ValueError(MP_ERROR_TEXT("must specify all of reset/dc pins"));
563 | }
564 |
565 | self->reset = mp_hal_get_pin_obj(args[ARG_reset].u_obj);
566 | self->dc = mp_hal_get_pin_obj(args[ARG_dc].u_obj);
567 |
568 | if (args[ARG_cs].u_obj != MP_OBJ_NULL) {
569 | self->cs = mp_hal_get_pin_obj(args[ARG_cs].u_obj);
570 | }
571 | if (args[ARG_backlight].u_obj != MP_OBJ_NULL) {
572 | self->backlight = mp_hal_get_pin_obj(args[ARG_backlight].u_obj);
573 | }
574 |
575 | return MP_OBJ_FROM_PTR(self);
576 | }
577 |
578 |
579 | STATIC uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
580 | return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
581 | }
582 |
583 |
584 | STATIC mp_obj_t st7789_color565(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
585 | return MP_OBJ_NEW_SMALL_INT(color565(
586 | (uint8_t)mp_obj_get_int(r),
587 | (uint8_t)mp_obj_get_int(g),
588 | (uint8_t)mp_obj_get_int(b)
589 | ));
590 | }
591 | STATIC MP_DEFINE_CONST_FUN_OBJ_3(st7789_color565_obj, st7789_color565);
592 |
593 |
594 | STATIC void map_bitarray_to_rgb565(uint8_t const *bitarray, uint8_t *buffer, int length, int width,
595 | uint16_t color, uint16_t bg_color) {
596 | int row_pos = 0;
597 | for (int i = 0; i < length; i++) {
598 | uint8_t byte = bitarray[i];
599 | for (int bi = 7; bi >= 0; bi--) {
600 | uint8_t b = byte & (1 << bi);
601 | uint16_t cur_color = b ? color : bg_color;
602 | *buffer = (cur_color & 0xff00) >> 8;
603 | buffer ++;
604 | *buffer = cur_color & 0xff;
605 | buffer ++;
606 |
607 | row_pos ++;
608 | if (row_pos >= width) {
609 | row_pos = 0;
610 | break;
611 | }
612 | }
613 | }
614 | }
615 |
616 |
617 | STATIC mp_obj_t st7789_map_bitarray_to_rgb565(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
618 | enum { ARG_bitarray, ARG_buffer, ARG_width, ARG_color, ARG_bg_color };
619 | static const mp_arg_t allowed_args[] = {
620 | { MP_QSTR_bitarray, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
621 | { MP_QSTR_buffer, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
622 | { MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = -1} },
623 | { MP_QSTR_color, MP_ARG_INT, {.u_int = WHITE} },
624 | { MP_QSTR_bg_color, MP_ARG_INT, {.u_int = BLACK } },
625 | };
626 | mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
627 | mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
628 |
629 | mp_buffer_info_t bitarray_info;
630 | mp_buffer_info_t buffer_info;
631 | mp_get_buffer_raise(args[ARG_bitarray].u_obj, &bitarray_info, MP_BUFFER_READ);
632 | mp_get_buffer_raise(args[ARG_buffer].u_obj, &buffer_info, MP_BUFFER_WRITE);
633 | mp_int_t width = args[ARG_width].u_int;
634 | mp_int_t color = args[ARG_color].u_int;
635 | mp_int_t bg_color = args[ARG_bg_color].u_int;
636 |
637 | map_bitarray_to_rgb565(bitarray_info.buf, buffer_info.buf, bitarray_info.len, width, color, bg_color);
638 |
639 | return mp_const_none;
640 | }
641 | STATIC MP_DEFINE_CONST_FUN_OBJ_KW(st7789_map_bitarray_to_rgb565_obj, 3, st7789_map_bitarray_to_rgb565);
642 |
643 |
644 | STATIC const mp_map_elem_t st7789_module_globals_table[] = {
645 | { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) },
646 | { MP_ROM_QSTR(MP_QSTR_color565), (mp_obj_t)&st7789_color565_obj },
647 | { MP_ROM_QSTR(MP_QSTR_map_bitarray_to_rgb565), (mp_obj_t)&st7789_map_bitarray_to_rgb565_obj },
648 | { MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&st7789_ST7789_type },
649 | { MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(BLACK) },
650 | { MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(BLUE) },
651 | { MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(RED) },
652 | { MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(GREEN) },
653 | { MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(CYAN) },
654 | { MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(MAGENTA) },
655 | { MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(YELLOW) },
656 | { MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(WHITE) },
657 | };
658 |
659 | STATIC MP_DEFINE_CONST_DICT (mp_module_st7789_globals, st7789_module_globals_table );
660 |
661 | const mp_obj_module_t mp_module_st7789 = {
662 | .base = { &mp_type_module },
663 | .globals = (mp_obj_dict_t*)&mp_module_st7789_globals,
664 | };
665 |
666 | MP_REGISTER_MODULE(MP_QSTR_st7789, mp_module_st7789, MODULE_ST7789_ENABLED);
667 |
--------------------------------------------------------------------------------
/st7789/st7789.h:
--------------------------------------------------------------------------------
1 | #ifndef __ST7789_H__
2 | #define __ST7789_H__
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 | #define ST7789_240x240_XSTART 0
9 | #define ST7789_240x240_YSTART 0
10 | #define ST7789_135x240_XSTART 52
11 | #define ST7789_135x240_YSTART 40
12 |
13 |
14 | // color modes
15 | #define COLOR_MODE_65K 0x50
16 | #define COLOR_MODE_262K 0x60
17 | #define COLOR_MODE_12BIT 0x03
18 | #define COLOR_MODE_16BIT 0x05
19 | #define COLOR_MODE_18BIT 0x06
20 | #define COLOR_MODE_16M 0x07
21 |
22 | // commands
23 | #define ST7789_NOP 0x00
24 | #define ST7789_SWRESET 0x01
25 | #define ST7789_RDDID 0x04
26 | #define ST7789_RDDST 0x09
27 |
28 | #define ST7789_SLPIN 0x10
29 | #define ST7789_SLPOUT 0x11
30 | #define ST7789_PTLON 0x12
31 | #define ST7789_NORON 0x13
32 |
33 | #define ST7789_INVOFF 0x20
34 | #define ST7789_INVON 0x21
35 | #define ST7789_DISPOFF 0x28
36 | #define ST7789_DISPON 0x29
37 | #define ST7789_CASET 0x2A
38 | #define ST7789_RASET 0x2B
39 | #define ST7789_RAMWR 0x2C
40 | #define ST7789_RAMRD 0x2E
41 |
42 | #define ST7789_PTLAR 0x30
43 | #define ST7789_COLMOD 0x3A
44 | #define ST7789_MADCTL 0x36
45 |
46 | #define ST7789_MADCTL_MY 0x80 // Page Address Order
47 | #define ST7789_MADCTL_MX 0x40 // Column Address Order
48 | #define ST7789_MADCTL_MV 0x20 // Page/Column Order
49 | #define ST7789_MADCTL_ML 0x10 // Line Address Order
50 | #define ST7789_MADCTL_MH 0x04 // Display Data Latch Order
51 | #define ST7789_MADCTL_RGB 0x00
52 | #define ST7789_MADCTL_BGR 0x08
53 |
54 | #define ST7789_RDID1 0xDA
55 | #define ST7789_RDID2 0xDB
56 | #define ST7789_RDID3 0xDC
57 | #define ST7789_RDID4 0xDD
58 |
59 | // Color definitions
60 | #define BLACK 0x0000
61 | #define BLUE 0x001F
62 | #define RED 0xF800
63 | #define GREEN 0x07E0
64 | #define CYAN 0x07FF
65 | #define MAGENTA 0xF81F
66 | #define YELLOW 0xFFE0
67 | #define WHITE 0xFFFF
68 |
69 | #ifdef __cplusplus
70 | }
71 | #endif /* __cplusplus */
72 |
73 | #endif /* __ST7789_H__ */
74 |
--------------------------------------------------------------------------------