pull/4/head
Ivan Belokobylskiy 2019-04-11 12:57:04 +03:00
rodzic 91afe52d36
commit fb42294e91
8 zmienionych plików z 845 dodań i 0 usunięć

5
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,5 @@
.vscode
.idea
*.o
*.P

21
LICENSE 100644
Wyświetl plik

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2019 Ivan Belokobylskiy
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.

179
README.md 100644
Wyświetl plik

@ -0,0 +1,179 @@
ST7789 Driver for MicroPython
=============================
Overview
--------
This is a driver for MicroPython to handle cheap displays
based on ST7789 chip.
<p align="center">
<img src="https://raw.githubusercontent.com/devbis/st7789_mpy/master/docs/ST7789.jpg" alt="ST7789 display photo"/>
</p>
It is written in pure C, so you have to build
firmware by yourself.
Only ESP8266 and ESP32 are supported for now.
Building instruction
---------------------
Prepare build tools as described in the manual.
You should follow the instruction for building MicroPython and
ensure that you can build the firmware without this display module.
Clone this module alongside the MPY sources:
$ git clone https://github.com/devbis/st7789_mpy.git
Go to MicroPython ports directory and for ESP8266 run:
$ cd micropython/ports/esp8266
for ESP32:
$ cd micropython/ports/esp32
And then compile the module with specified USER_C_MODULES dir
$ make USER_C_MODULES=../../../st7789_mpy/ all
If you have other user modules, copy the st7789_driver/st7789 to
the user modules directory
Upload the resulting firmware to your MCU as usual with esptool.py
(See
[MicroPython docs](http://docs.micropython.org/en/latest/esp8266/tutorial/intro.html#deploying-the-firmware)
for more info)
Working examples
----------------
This module was tested on ESP32 and ESP8266 MCUs.
You have to provide `machine.SPI` object and at least two pins for RESET and
DC pins on the screen for the display object.
# ESP 8266
import machine
import st7789
spi = machine.SPI(1, baudrate=40000000, polarity=1)
display = st7789.ST7789(spi, 240, 240, reset=machine.Pin(5, machine.Pin.OUT), dc=machine.Pin(4, machine.Pin.OUT))
For ESP32 modules you have to provide specific pins for SPI.
Unfortunately, I was unable to run this display on SPI(1) interface.
For machine.SPI(2) == VSPI you have to use
- CLK: Pin(18)
- MOSI: Pin(23)
Other SPI pins are not used.
# ESP32
import machine
import st7789
spi = machine.SPI(2, baudrate=40000000, polarity=1, sck=machine.Pin(18), mosi=machine.Pin(23))
display = st7789.ST7789(spi, 240, 240, reset=machine.Pin(4, machine.Pin.OUT), dc=machine.Pin(2, machine.Pin.OUT))
I couldn't run the display on an SPI with baudrate higher than 40MHZ
Methods
-------------
This driver supports only 16bit colors in RGB565 notation.
- `ST7789.fill(color)`
Fill the entire display with the specified color.
- `ST7789.pixel(x, y, color)`
Set the specified pixel to the given color.
- `ST7789.line(x0, y0, x1, y1, color)`
Draws a single line with the provided `color` from (`x0`, `y0`) to
(`x1`, `y1`).
- `ST7789.hline(x, y, length, color)`
Draws a single horizontal line with the provided `color` and `length`
in pixels. Along with `vline`, this is a fast version with reduced
number of SPI calls.
- `ST7789.vline(x, y, length, color)`
Draws a single horizontal line with the provided `color` and `length`
in pixels.
- `ST7789.rect(x, y, width, height, color)`
Draws a rectangle from (`x`, `y`) with corresponding dimensions
- `ST7789.fill_rect(x, y, width, height, color)`
Fill a rectangle starting from (`x`, `y`) coordinates
- `ST7789.blit_buffer(buffer, x, y, width, height)`
Copy bytes() or bytearray() content to the screen internal memory.
Note: every color requires 2 bytes in the array
Also, the module exposes predefined colors:
`BLACK`, `BLUE`, `RED`, `GREEN`, `CYAN`, `MAGENTA`, `YELLOW`, and `WHITE`
Performance
-----------
For the comparison I used an excelent library for Arduino
that can handle this screen.
https://github.com/ananevilya/Arduino-ST7789-Library/
Also, I used my slow driver for this screen, written in pure python.
https://github.com/devbis/st7789py_mpy/
I used these modules to draw a line from 0,0 to 239,239
The table represents the time in milliseconds for each case
| | Arduino-ST7789 | st7789py_mpy | st7789_mpy |
|---------|----------------|--------------|---------------|
| ESP8266 | 26 | 450 | 12 |
| ESP32 | 23 | 450 | 47 |
As you can see, the ESP32 module draws a line 4 times slower than
the older ESP8266 module.
Troubleshooting
---------------
#### Overflow of iram1_0_seg
When building a firmware for esp8266 you can see this failure message from
the linker:
LINK build/firmware.elf
xtensa-lx106-elf-ld: build/firmware.elf section `.text' will not fit in region `iram1_0_seg'
xtensa-lx106-elf-ld: region `iram1_0_seg' overflowed by 292 bytes
Makefile:192: recipe for target 'build/firmware.elf' failed
To fix this issue, you have to put st7789 module to irom0 section.
Edit `esp8266_common.ld` file in the `ports/esp8266` dir and add a line
*st7789/*.o(.literal* .text*)
in the `.irom0.text : ALIGN(4)` section

1
VERSION 100644
Wyświetl plik

@ -0,0 +1 @@
0.1.0

BIN
docs/ST7789.jpg 100644

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 40 KiB

Wyświetl plik

@ -0,0 +1,6 @@
ST7789_MOD_DIR := $(USERMOD_DIR)
SRC_USERMOD += $(addprefix $(ST7789_MOD_DIR)/, \
st7789.c \
)
CFLAGS_USERMOD += -I$(ST7789_MOD_DIR) -DMODULE_ST7789_ENABLED=1
# CFLAGS_USERMOD += -DEXPOSE_EXTRA_METHODS=1

559
st7789/st7789.c 100644
Wyświetl plik

@ -0,0 +1,559 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ivan Belokobylskiy
*
* 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.
*/
#define __ST7789_VERSION__ "0.1.0"
#include "py/obj.h"
#include "py/runtime.h"
#include "py/builtin.h"
#include "py/mphal.h"
#include "extmod/machine_spi.h"
#include "st7789.h"
#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
#define ABS(N) ((N<0)?(-N):(N))
#define mp_hal_delay_ms(delay) (mp_hal_delay_us(delay * 1000))
#define CS_LOW() { if(self->cs) {mp_hal_pin_write(self->cs, 0);} }
#define CS_HIGH() { if(self->cs) {mp_hal_pin_write(self->cs, 1);} }
#define DC_LOW() (mp_hal_pin_write(self->dc, 0))
#define DC_HIGH() (mp_hal_pin_write(self->dc, 1))
#define RESET_LOW() (mp_hal_pin_write(self->reset, 0))
#define RESET_HIGH() (mp_hal_pin_write(self->reset, 1))
STATIC void write_spi(mp_obj_base_t *spi_obj, const uint8_t *buf, int len) {
mp_machine_spi_p_t *spi_p = (mp_machine_spi_p_t*)spi_obj->type->protocol;
spi_p->transfer(spi_obj, len, buf, NULL);
}
// this is the actual C-structure for our new object
typedef struct _st7789_ST7789_obj_t {
mp_obj_base_t base;
mp_obj_base_t *spi_obj;
uint8_t width;
uint8_t height;
mp_hal_pin_obj_t reset;
mp_hal_pin_obj_t dc;
mp_hal_pin_obj_t cs;
mp_hal_pin_obj_t backlight;
} st7789_ST7789_obj_t;
// just a definition
mp_obj_t st7789_ST7789_make_new( const mp_obj_type_t *type,
size_t n_args,
size_t n_kw,
const mp_obj_t *args );
STATIC void st7789_ST7789_print( const mp_print_t *print,
mp_obj_t self_in,
mp_print_kind_t kind ) {
(void)kind;
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_printf(print, "<ST7789 width=%u, height=%u, spi=%p>", self->width, self->height, self->spi_obj);
}
/* methods start */
STATIC void write_cmd(st7789_ST7789_obj_t *self, uint8_t cmd, const uint8_t *data, int len) {
CS_LOW()
if (cmd) {
DC_LOW();
write_spi(self->spi_obj, &cmd, 1);
}
if (len > 0) {
DC_HIGH();
write_spi(self->spi_obj, data, len);
}
CS_HIGH()
}
STATIC void set_window(st7789_ST7789_obj_t *self, uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
if (x0 > x1 || x1 > self->width) {
return;
}
if (y0 > y1 || y1 > self->height) {
return;
}
uint8_t bufx[4] = {x0 >> 8, x0 & 0xFF, x1 >> 8, x1 & 0xFF};
uint8_t bufy[4] = {y0 >> 8, y0 & 0xFF, y1 >> 8, y1 & 0xFF};
write_cmd(self, ST7789_CASET, bufx, 4);
write_cmd(self, ST7789_RASET, bufy, 4);
write_cmd(self, ST7789_RAMWR, NULL, 0);
}
STATIC void draw_pixel(st7789_ST7789_obj_t *self, uint8_t x, uint8_t y, uint16_t color) {
uint8_t hi = color >> 8, lo = color;
set_window(self, x, y, x, y);
DC_HIGH();
CS_LOW();
write_spi(self->spi_obj, &hi, 1);
write_spi(self->spi_obj, &lo, 1);
CS_HIGH();
}
STATIC mp_obj_t st7789_ST7789_hard_reset(mp_obj_t self_in) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
CS_LOW();
RESET_HIGH();
mp_hal_delay_ms(50);
RESET_LOW();
mp_hal_delay_ms(50);
RESET_HIGH();
mp_hal_delay_ms(150);
CS_HIGH();
return mp_const_none;
}
STATIC mp_obj_t st7789_ST7789_soft_reset(mp_obj_t self_in) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
write_cmd(self, ST7789_SWRESET, NULL, 0);
mp_hal_delay_ms(150);
return mp_const_none;
}
// do not expose extra method to reduce size
#ifdef EXPOSE_EXTRA_METHODS
STATIC mp_obj_t st7789_ST7789_write(mp_obj_t self_in, mp_obj_t command, mp_obj_t data) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_buffer_info_t src;
if (data == mp_const_none) {
write_cmd(self, (uint8_t)mp_obj_get_int(command), NULL, 0);
} else {
mp_get_buffer_raise(data, &src, MP_BUFFER_READ);
write_cmd(self, (uint8_t)mp_obj_get_int(command), (const uint8_t*)src.buf, src.len);
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_3(st7789_ST7789_write_obj, st7789_ST7789_write);
MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_hard_reset_obj, st7789_ST7789_hard_reset);
MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_soft_reset_obj, st7789_ST7789_soft_reset);
STATIC mp_obj_t st7789_ST7789_sleep_mode(mp_obj_t self_in, mp_obj_t value) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
if(mp_obj_is_true(value)) {
write_cmd(self, ST7789_SLPIN, NULL, 0);
} else {
write_cmd(self, ST7789_SLPOUT, NULL, 0);
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_sleep_mode_obj, st7789_ST7789_sleep_mode);
STATIC mp_obj_t st7789_ST7789_set_window(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x0 = mp_obj_get_int(args[1]);
mp_int_t x1 = mp_obj_get_int(args[2]);
mp_int_t y0 = mp_obj_get_int(args[3]);
mp_int_t y1 = mp_obj_get_int(args[4]);
set_window(self, x0, y0, x1, y1);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_set_window_obj, 5, 5, st7789_ST7789_set_window);
#endif
STATIC mp_obj_t st7789_ST7789_inversion_mode(mp_obj_t self_in, mp_obj_t value) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
if(mp_obj_is_true(value)) {
write_cmd(self, ST7789_INVON, NULL, 0);
} else {
write_cmd(self, ST7789_INVOFF, NULL, 0);
}
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_inversion_mode_obj, st7789_ST7789_inversion_mode);
STATIC void fill_color_buffer(mp_obj_base_t* spi_obj, uint16_t color, int length) {
uint8_t hi = color >> 8, lo = color;
const int buffer_pixel_size = 128;
int chunks = length / buffer_pixel_size;
int rest = length % buffer_pixel_size;
uint8_t buffer[buffer_pixel_size * 2]; // 128 pixels
// fill buffer with color data
for (int i = 0; i < length && i < buffer_pixel_size; i++) {
buffer[i*2] = hi;
buffer[i*2 + 1] = lo;
}
if (chunks) {
for (int j = 0; j < chunks; j ++) {
write_spi(spi_obj, buffer, buffer_pixel_size*2);
}
}
if (rest) {
write_spi(spi_obj, buffer, rest*2);
}
}
STATIC mp_obj_t st7789_ST7789_fill_rect(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]);
mp_int_t color = mp_obj_get_int(args[5]);
set_window(self, x, y, x + w - 1, y + h - 1);
DC_HIGH();
CS_LOW();
fill_color_buffer(self->spi_obj, color, w * h);
CS_HIGH();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_fill_rect_obj, 6, 6, st7789_ST7789_fill_rect);
STATIC mp_obj_t st7789_ST7789_fill(mp_obj_t self_in, mp_obj_t _color) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
mp_int_t color = mp_obj_get_int(_color);
set_window(self, 0, 0, self->width, self->height);
DC_HIGH();
CS_LOW();
fill_color_buffer(self->spi_obj, color, self->width * self->height);
CS_HIGH();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(st7789_ST7789_fill_obj, st7789_ST7789_fill);
STATIC mp_obj_t st7789_ST7789_pixel(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t color = mp_obj_get_int(args[3]);
draw_pixel(self, x, y, color);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_pixel_obj, 4, 4, st7789_ST7789_pixel);
STATIC mp_obj_t st7789_ST7789_line(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x0 = mp_obj_get_int(args[1]);
mp_int_t y0 = mp_obj_get_int(args[2]);
mp_int_t x1 = mp_obj_get_int(args[3]);
mp_int_t y1 = mp_obj_get_int(args[4]);
mp_int_t color = mp_obj_get_int(args[5]);
int16_t steep = ABS(y1 - y0) > ABS(x1 - x0);
if (steep) {
_swap_int16_t(x0, y0);
_swap_int16_t(x1, y1);
}
if (x0 > x1) {
_swap_int16_t(x0, x1);
_swap_int16_t(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = ABS(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if (y0 < y1) {
ystep = 1;
} else {
ystep = -1;
}
for (; x0<=x1; x0++) {
if (steep) {
draw_pixel(self, y0, x0, color);
} else {
draw_pixel(self, x0, y0, color);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_line_obj, 6, 6, st7789_ST7789_line);
STATIC mp_obj_t st7789_ST7789_blit_buffer(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_buffer_info_t buf_info;
mp_get_buffer_raise(args[1], &buf_info, MP_BUFFER_READ);
mp_int_t x = mp_obj_get_int(args[2]);
mp_int_t y = mp_obj_get_int(args[3]);
mp_int_t w = mp_obj_get_int(args[4]);
mp_int_t h = mp_obj_get_int(args[5]);
set_window(self, x, y, x + w - 1, y + h - 1);
DC_HIGH();
CS_LOW();
const int buf_size = 256;
int i = 0;
int chunks = buf_info.len / buf_size;
int rest = buf_info.len % buf_size;
for (; i < chunks; i ++) {
write_spi(self->spi_obj, (const uint8_t*)buf_info.buf + i*buf_size, buf_size);
}
if (rest) {
write_spi(self->spi_obj, (const uint8_t*)buf_info.buf + i*buf_size, rest);
}
CS_HIGH();
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_blit_buffer_obj, 6, 6, st7789_ST7789_blit_buffer);
STATIC mp_obj_t st7789_ST7789_init(mp_obj_t self_in) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(self_in);
st7789_ST7789_hard_reset(self_in);
st7789_ST7789_soft_reset(self_in);
write_cmd(self, ST7789_SLPOUT, NULL, 0);
const uint8_t color_mode[] = { COLOR_MODE_65K | COLOR_MODE_16BIT};
write_cmd(self, ST7789_COLMOD, color_mode, 1);
mp_hal_delay_ms(10);
const uint8_t madctl[] = { ST7789_MADCTL_ML | ST7789_MADCTL_RGB };
write_cmd(self, ST7789_MADCTL, madctl, 1);
write_cmd(self, ST7789_INVON, NULL, 0);
mp_hal_delay_ms(10);
write_cmd(self, ST7789_NORON, NULL, 0);
mp_hal_delay_ms(10);
const mp_obj_t args[] = {
self_in,
mp_obj_new_int(0),
mp_obj_new_int(0),
mp_obj_new_int(self->width),
mp_obj_new_int(self->height),
mp_obj_new_int(BLACK)
};
st7789_ST7789_fill_rect(6, args);
write_cmd(self, ST7789_DISPON, NULL, 0);
mp_hal_delay_ms(500);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(st7789_ST7789_init_obj, st7789_ST7789_init);
STATIC void fast_hline(st7789_ST7789_obj_t *self, uint8_t x, uint8_t y, uint16_t w, uint16_t color) {
set_window(self, x, y, x + w - 1, y);
DC_HIGH();
CS_LOW();
fill_color_buffer(self->spi_obj, color, w);
CS_HIGH();
}
STATIC void fast_vline(st7789_ST7789_obj_t *self, uint8_t x, uint8_t y, uint16_t w, uint16_t color) {
set_window(self, x, y, x, y + w - 1);
DC_HIGH();
CS_LOW();
fill_color_buffer(self->spi_obj, color, w);
CS_HIGH();
}
STATIC mp_obj_t st7789_ST7789_hline(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t color = mp_obj_get_int(args[4]);
fast_hline(self, x, y, w, color);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_hline_obj, 5, 5, st7789_ST7789_hline);
STATIC mp_obj_t st7789_ST7789_vline(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t color = mp_obj_get_int(args[4]);
fast_vline(self, x, y, w, color);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_vline_obj, 5, 5, st7789_ST7789_vline);
STATIC mp_obj_t st7789_ST7789_rect(size_t n_args, const mp_obj_t *args) {
st7789_ST7789_obj_t *self = MP_OBJ_TO_PTR(args[0]);
mp_int_t x = mp_obj_get_int(args[1]);
mp_int_t y = mp_obj_get_int(args[2]);
mp_int_t w = mp_obj_get_int(args[3]);
mp_int_t h = mp_obj_get_int(args[4]);
mp_int_t color = mp_obj_get_int(args[5]);
fast_hline(self, x, y, w, color);
fast_vline(self, x, y, h, color);
fast_hline(self, x, y + h - 1, w, color);
fast_vline(self, x + w - 1, y, h, color);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(st7789_ST7789_rect_obj, 6, 6, st7789_ST7789_rect);
STATIC const mp_rom_map_elem_t st7789_ST7789_locals_dict_table[] = {
// Do not expose internal functions to fit iram_0 section
#ifdef EXPOSE_EXTRA_METHODS
{ MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&st7789_ST7789_write_obj) },
{ MP_ROM_QSTR(MP_QSTR_hard_reset), MP_ROM_PTR(&st7789_ST7789_hard_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_soft_reset), MP_ROM_PTR(&st7789_ST7789_soft_reset_obj) },
{ MP_ROM_QSTR(MP_QSTR_sleep_mode), MP_ROM_PTR(&st7789_ST7789_sleep_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_inversion_mode), MP_ROM_PTR(&st7789_ST7789_inversion_mode_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_window), MP_ROM_PTR(&st7789_ST7789_set_window_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&st7789_ST7789_init_obj) },
{ MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&st7789_ST7789_pixel_obj) },
{ MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&st7789_ST7789_line_obj) },
{ MP_ROM_QSTR(MP_QSTR_blit_buffer), MP_ROM_PTR(&st7789_ST7789_blit_buffer_obj) },
{ MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&st7789_ST7789_fill_rect_obj) },
{ MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&st7789_ST7789_fill_obj) },
{ MP_ROM_QSTR(MP_QSTR_hline), MP_ROM_PTR(&st7789_ST7789_hline_obj) },
{ MP_ROM_QSTR(MP_QSTR_vline), MP_ROM_PTR(&st7789_ST7789_vline_obj) },
{ MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&st7789_ST7789_rect_obj) },
};
STATIC MP_DEFINE_CONST_DICT(st7789_ST7789_locals_dict, st7789_ST7789_locals_dict_table);
/* methods end */
const mp_obj_type_t st7789_ST7789_type = {
{ &mp_type_type },
.name = MP_QSTR_ST7789,
.print = st7789_ST7789_print,
.make_new = st7789_ST7789_make_new,
.locals_dict = (mp_obj_dict_t*)&st7789_ST7789_locals_dict,
};
mp_obj_t st7789_ST7789_make_new(const mp_obj_type_t *type,
size_t n_args,
size_t n_kw,
const mp_obj_t *all_args ) {
enum { ARG_spi, ARG_width, ARG_height, ARG_reset, ARG_dc, ARG_cs, ARG_backlight };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_spi, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_width, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
{ MP_QSTR_height, MP_ARG_INT | MP_ARG_REQUIRED, {.u_int = 0} },
{ MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_dc, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_backlight, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
// create new object
st7789_ST7789_obj_t *self = m_new_obj(st7789_ST7789_obj_t);
self->base.type = &st7789_ST7789_type;
// set parameters
mp_obj_base_t *spi_obj = (mp_obj_base_t*)MP_OBJ_TO_PTR(args[ARG_spi].u_obj);
self->spi_obj = spi_obj;
self->width = args[ARG_width].u_int;
self->height = args[ARG_height].u_int;
if (args[ARG_reset].u_obj == MP_OBJ_NULL
|| args[ARG_dc].u_obj == MP_OBJ_NULL) {
mp_raise_ValueError("must specify all of reset/dc pins");
}
self->reset = mp_hal_get_pin_obj(args[ARG_reset].u_obj);
self->dc = mp_hal_get_pin_obj(args[ARG_dc].u_obj);
if (args[ARG_cs].u_obj != MP_OBJ_NULL) {
self->cs = mp_hal_get_pin_obj(args[ARG_cs].u_obj);
}
if (args[ARG_backlight].u_obj != MP_OBJ_NULL) {
self->backlight = mp_hal_get_pin_obj(args[ARG_backlight].u_obj);
}
return MP_OBJ_FROM_PTR(self);
}
STATIC uint16_t color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}
STATIC mp_obj_t st7789_color565(mp_obj_t r, mp_obj_t g, mp_obj_t b) {
return MP_OBJ_NEW_SMALL_INT(color565(
(uint8_t)mp_obj_get_int(r),
(uint8_t)mp_obj_get_int(g),
(uint8_t)mp_obj_get_int(b)
));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(st7789_color565_obj, st7789_color565);
STATIC const mp_map_elem_t st7789_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_st7789) },
{ MP_ROM_QSTR(MP_QSTR_color565), (mp_obj_t)&st7789_color565_obj },
{ MP_ROM_QSTR(MP_QSTR_ST7789), (mp_obj_t)&st7789_ST7789_type },
{ MP_ROM_QSTR(MP_QSTR_BLACK), MP_ROM_INT(BLACK) },
{ MP_ROM_QSTR(MP_QSTR_BLUE), MP_ROM_INT(BLUE) },
{ MP_ROM_QSTR(MP_QSTR_RED), MP_ROM_INT(RED) },
{ MP_ROM_QSTR(MP_QSTR_GREEN), MP_ROM_INT(GREEN) },
{ MP_ROM_QSTR(MP_QSTR_CYAN), MP_ROM_INT(CYAN) },
{ MP_ROM_QSTR(MP_QSTR_MAGENTA), MP_ROM_INT(MAGENTA) },
{ MP_ROM_QSTR(MP_QSTR_YELLOW), MP_ROM_INT(YELLOW) },
{ MP_ROM_QSTR(MP_QSTR_WHITE), MP_ROM_INT(WHITE) },
};
STATIC MP_DEFINE_CONST_DICT (mp_module_st7789_globals, st7789_module_globals_table );
const mp_obj_module_t mp_module_st7789 = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_st7789_globals,
};
MP_REGISTER_MODULE(MP_QSTR_st7789, mp_module_st7789, MODULE_ST7789_ENABLED);

74
st7789/st7789.h 100644
Wyświetl plik

@ -0,0 +1,74 @@
#ifndef __ST7789_H__
#define __ST7789_H__
#ifdef __cplusplus
extern "C" {
#endif
#define ST7789_TFTWIDTH_240 240
#define ST7789_TFTHEIGHT_240 240
#define ST7789_240x240_XSTART 0
#define ST7789_240x240_YSTART 0
// color modes
#define COLOR_MODE_65K 0x50
#define COLOR_MODE_262K 0x60
#define COLOR_MODE_12BIT 0x03
#define COLOR_MODE_16BIT 0x05
#define COLOR_MODE_18BIT 0x06
#define COLOR_MODE_16M 0x07
// commands
#define ST7789_NOP 0x00
#define ST7789_SWRESET 0x01
#define ST7789_RDDID 0x04
#define ST7789_RDDST 0x09
#define ST7789_SLPIN 0x10
#define ST7789_SLPOUT 0x11
#define ST7789_PTLON 0x12
#define ST7789_NORON 0x13
#define ST7789_INVOFF 0x20
#define ST7789_INVON 0x21
#define ST7789_DISPOFF 0x28
#define ST7789_DISPON 0x29
#define ST7789_CASET 0x2A
#define ST7789_RASET 0x2B
#define ST7789_RAMWR 0x2C
#define ST7789_RAMRD 0x2E
#define ST7789_PTLAR 0x30
#define ST7789_COLMOD 0x3A
#define ST7789_MADCTL 0x36
#define ST7789_MADCTL_MY 0x80 // Page Address Order
#define ST7789_MADCTL_MX 0x40 // Column Address Order
#define ST7789_MADCTL_MV 0x20 // Page/Column Order
#define ST7789_MADCTL_ML 0x10 // Line Address Order
#define ST7789_MADCTL_MH 0x04 // Display Data Latch Order
#define ST7789_MADCTL_RGB 0x00
#define ST7789_MADCTL_BGR 0x08
#define ST7789_RDID1 0xDA
#define ST7789_RDID2 0xDB
#define ST7789_RDID3 0xDC
#define ST7789_RDID4 0xDD
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __ST7789_H__ */