commit 9df7862e97bde5af89fc307516adf5784a1a7c9c Author: Dejvino Date: Sat Aug 1 19:49:42 2020 +0000 Initial working version diff --git a/font8x8_basic.h b/font8x8_basic.h new file mode 100644 index 0000000..125cf16 --- /dev/null +++ b/font8x8_basic.h @@ -0,0 +1,152 @@ +/** + * 8x8 monochrome bitmap fonts for rendering + * Author: Daniel Hepper + * + * License: Public Domain + * + * Based on: + * // Summary: font8x8.h + * // 8x8 monochrome bitmap fonts for rendering + * // + * // Author: + * // Marcel Sondaar + * // International Business Machines (public domain VGA fonts) + * // + * // License: + * // Public Domain + * + * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm + **/ + +// Constant: font8x8_basic +// Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin) +char font8x8_basic[128][8] = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) + { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) + { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") + { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) + { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) + { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) + { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) + { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') + { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() + { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) + { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) + { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) + { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) + { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) + { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) + { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) + { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) + { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) + { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) + { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) + { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) + { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) + { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) + { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) + { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) + { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) + { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) + { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) + { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) + { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) + { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) + { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) + { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) + { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) + { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) + { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) + { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) + { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) + { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) + { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) + { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) + { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) + { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) + { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) + { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) + { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) + { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) + { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) + { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) + { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) + { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) + { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) + { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) + { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) + { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) + { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) + { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) + { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) + { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) + { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) + { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) + { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) + { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) + { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) + { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) + { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) + { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) + { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) + { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) + { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) + { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) + { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) + { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) + { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) + { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) + { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) + { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) + { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) + { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) + { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) + { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) + { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) + { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) + { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) + { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) + { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F +}; diff --git a/main.c b/main.c new file mode 100644 index 0000000..654e188 --- /dev/null +++ b/main.c @@ -0,0 +1,75 @@ +#include +#include "st7735.h" +#include + +int main(int argc, char *argv[]) +{ + setbuf(stdout, NULL); + + wiringPiSetup(); + + lcd_t* lcd = lcd_init(40000000, 10, 2, 0); + + printf("Fill display..."); + printf("blue..."); + lcd_fillScreen(0, 70, 160); + delay(1000); + printf("black..."); + lcd_fillScreen(0, 0, 0); + printf("DONE\n"); + delay(1000); + + /* Draw the lines */ + /*printf("Lines..."); + lcdst_drawHLine(0, 149, 128, 0, 255, 255); + lcdst_drawHLine(0, 139, 128, 255, 255, 0); + lcdst_drawVLine(117, 0, 160, 0, 255, 255); + lcdst_drawVLine(107, 0, 160, 255, 255, 0); + printf("DONE\n");*/ + + /*printf("Points..."); + for (int i = 1; i < 20; i++) { + lcdst_drawPx(5 - 1, 70 + i, 100, 100, 100); + lcdst_drawPx(5 + i + 1, 70 + i, 100, 100, 100); + } + printf("DONE\n"); + + printf("Triangle..."); + for (int i = 1; i < 20; i++) { + lcdst_drawHLine(5, 70 + i, i, 255, 0, 0); + } + printf("DONE\n");*/ + + printf("Rectangles..."); + //printf("outline..."); + //lcd_drawRect(10, 10, 10, 10, 0, 255, 255); + //lcd_drawRect(10, 30, 10, 10, 255, 255, 0); + printf("filled..."); + lcd_fillRect(30, 10, 10, 10, 0, 255, 255); + lcd_fillRect(30, 30, 10, 10, 255, 255, 0); + printf("bunch..."); + for (int i = 0; i < 40; i++) { + lcd_fillRect(40 + (i%13) * 4, 40 + (i%19) * 4, 20, 20, i % 5 * 15, i % 7 * 17, i % 3 * 23); + } + printf("DONE\n"); + + printf("Text..."); + lcd_printChar(10, 90, 'A'); + lcd_printText(10, 50, "Ahoj!"); + lcd_printChar(10, 100, 'Z'); + printf("DONE\n"); + + /* Send the raw data */ +/* printf("Raw..."); + lcdst_setWindow(20, 20, 29, 29); + for(uint8 i=0; i<100; i++) lcdst_pushPx(255, 0, 255); + lcdst_setWindow(0, 0, 127, 159); + printf("DONE\n");*/ + + + /* Uninitialize the display */ + //lcd_deinit(lcd); + + return 0; +} + diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..75fd70a --- /dev/null +++ b/meson.build @@ -0,0 +1,3 @@ +project('dejvino-ST7735', 'c') +src = ['main.c', 'st7735.c'] +executable('st7735', src, link_args: '-lwiringPi') diff --git a/st7735.c b/st7735.c new file mode 100644 index 0000000..ca53f6b --- /dev/null +++ b/st7735.c @@ -0,0 +1,332 @@ +#include +#include +#include +#include "st7735.h" +#include "font8x8_basic.h" + +/********************************** EASY PORT *********************************/ +/* + * If you porting this code, you can change below headers and function pointers + * in gpio structure. + */ +#include +#include +struct +{ + void (* const delay)(unsigned int milliseconds); + void (* const pinMode)(int pin, int mode); + void (* const digitalWrite)(int pin, int value); + int (* const spiSetup)(int channel, int speed); + int (* const spiDataRW)(int channel, uint8 *data, int length); +} static const gpio = +{ + delay, + pinMode, + digitalWrite, + wiringPiSPISetup, + wiringPiSPIDataRW +}; +/****************************** END EASY PORT END *****************************/ + +/* The global variable that stores the pointer to the structure, + * with the current active display. + */ +static lcd_t *activeDisplay; + +/* + * Safe allocation of the memory block. + * + * Parameters: + * size - Size of memory block to allocate. + * + * Return: + * Pointer to the memory block. If an error occurs, stop the program. + */ +static inline void *safeMalloc(size_t size) +{ + void *memoryBlock = (void*) malloc(size); + + /* Check the pointer */ + if(memoryBlock == NULL) + { + fprintf(stderr, "Out of RAM memory!\n"); + exit(EXIT_FAILURE); + } + + return memoryBlock; +} /* safeMalloc */ + + +void lcd_setOrientation(uint8 orientation); +void lcd_setGamma(uint8 state); +void lcd_pushPx(uint8 r, uint8 g, uint8 b); +void lcd_pushPixels(uint8* pixels, size_t count); +void lcd_pushChar(char c); + +/* + * Write the command to the display driver. + * + * Parameters: + * cmd - The command to write. + */ +static inline void writeCommand(uint8 cmd) +{ + gpio.digitalWrite(activeDisplay->a0, LOW); + gpio.spiDataRW(activeDisplay->cs, &cmd, 1); +} /* writeCommand */ + +/* + * Write the data to the display driver. + * + * Parameters: + * data - The data to write. + */ +static inline void writeData(uint8 data) +{ + gpio.digitalWrite(activeDisplay->a0, HIGH); + gpio.spiDataRW(activeDisplay->cs, &data, 1); +} /* writeData */ + +lcd_t *lcd_init(int spiSpeed, int cs, int a0, int rs) +{ + /* Create the one instance of the lcdst_t structure and activate it */ + lcd_t *instance = (lcd_t *) safeMalloc(sizeof(lcd_t)); + + activeDisplay = instance; + + /* Assign specific pins */ + instance->cs = cs; + instance->a0 = a0; + instance->rs = rs; + /* + * instance->width; instance->height + * The setting of this variables will take place + * in the function lcdst_setOrientation() below. + */ + + /* Configure the a0 pin. The logic level is not significant now. */ + gpio.pinMode(instance->a0, OUTPUT); + + /* If the rs pin is connected then configure it */ + if(instance->rs != -1) + { + gpio.pinMode(instance->rs, OUTPUT); + gpio.digitalWrite(instance->rs, HIGH); /* Reset OFF */ + gpio.delay(10); + } + + /* Configure the SPI interface */ + if(gpio.spiSetup(instance->cs, spiSpeed) == -1) + { + fprintf(stderr, "Failed to setup the SPI interface!\n"); + exit(EXIT_FAILURE); + } + + /* Software reset; Wait minimum 120ms */ + writeCommand(0x01); + gpio.delay(150); + + /* Sleep out; Wait minimum 120ms */ + writeCommand(0x11); + gpio.delay(150); + + /* Set the orientation and the gamma */ + lcd_setOrientation(0); + lcd_setGamma(2); /* Optional */ + + /* Set the pixel format */ + writeCommand(0x3A); + writeData(0x06); + + /* Display ON; Wait 100ms before start */ + writeCommand(0x29); + gpio.delay(100); + + return instance; +} /* lcd_init */ + +void lcd_deinit(lcd_t *display) +{ + if(display == NULL) return; + + free(display); +} /* lcdst_uninit */ + +void lcd_setOrientation(uint8 orientation) +{ + writeCommand(0x36); /* Memory Data Access Control */ + + switch(orientation) + { + case 1: + writeData(0x60); /* MX + MV */ + activeDisplay->width = 160; + activeDisplay->height = 128; + lcd_setWindow(0, 0, 159, 127); + break; + + case 2: + writeData(0xC0); /* MY + MX */ + activeDisplay->width = 128; + activeDisplay->height = 160; + lcd_setWindow(0, 0, 127, 159); + break; + + case 3: + writeData(0xA0); /* MY + MV */ + activeDisplay->width = 160; + activeDisplay->height = 128; + lcd_setWindow(0, 0, 159, 127); + break; + + default: + writeData(0x00); /* None */ + activeDisplay->width = 128; + activeDisplay->height = 160; + lcd_setWindow(0, 0, 127, 159); + break; + } +} /* lcdst_setOrientation */ + +void lcd_setGamma(uint8 state) +{ + /* The status (0 or 1) of the GS pin can only be empirically tested */ + switch(state) + { + case 1: state = 2; break; /* GS_pin=1: 1.8; GS_pin=0: 2.5 */ + case 2: state = 4; break; /* GS_pin=1: 2.5; GS_pin=0: 2.2 */ + case 3: state = 8; break; /* GS_pin=1: 1.0; GS_pin=0: 1.8 */ + default: state = 1; break; /* GS_pin=1: 2.2; GS_pin=0: 1.0 */ + } + + /* Set built-in gamma */ + writeCommand(0x26); + writeData(state); +} /* lcdst_setGamma */ + +void lcd_setInversion(uint8 state) +{ + /* Display inversion ON/OFF */ + writeCommand(state ? 0x21 : 0x20); +} /* lcdst_setInversion */ + +uint8 lcd_setWindow(uint8 x1, uint8 y1, uint8 x2, uint8 y2) +{ + /* Accept: 0 <= x1 <= x2 < activeDisplay->width */ + if(x2 < x1) return 1; + if(x2 >= activeDisplay->width) return 1; + + /* Accept: 0 <= y1 <= y2 < activeDisplay->height */ + if(y2 < y1) return 1; + if(y2 >= activeDisplay->height) return 1; + + /* Set column address */ + writeCommand(0x2A); + writeData(0); writeData(x1); + writeData(0); writeData(x2); + + /* Set row address */ + writeCommand(0x2B); + writeData(0); writeData(y1); + writeData(0); writeData(y2); + + /* Activate RAW write */ + writeCommand(0x2C); + //gpio.delay(5); + + return 0; +} /* lcdst_setWindow */ + +void lcd_activateRamWrite(void) +{ + writeCommand(0x2C); + //gpio.delay(5); +} /* lcdst_activateRamWrite */ + +uint8 pixel[3]; + +inline void lcd_pushPx(uint8 r, uint8 g, uint8 b) +{ + gpio.digitalWrite(activeDisplay->a0, HIGH); + pixel[0] = r; + pixel[1] = g; + pixel[2] = b; + gpio.spiDataRW(activeDisplay->cs, pixel, 3); +} /* lcdst_pushPx */ + +void lcd_pushPixels(uint8* pixels, size_t count) +{ + gpio.digitalWrite(activeDisplay->a0, HIGH); + gpio.spiDataRW(activeDisplay->cs, pixels, count * 3); +} + +void lcd_drawPx(uint8 x, uint8 y, uint8 r, uint8 g, uint8 b) +{ + if(lcd_setWindow(x, y, x, y)) return; + lcd_pushPx(r, g, b); +} /* lcdst_drawPx */ + +void lcd_fillRect(uint8 x, uint8 y, uint8 w, uint8 h, + uint8 r, uint8 g, uint8 b) +{ + /* Draw only in the display space */ + if((w == 0) || (h == 0)) return; + if((x+w-1) >= activeDisplay->width) w = activeDisplay->width - x; + if((y+h-1) >= activeDisplay->height) h = activeDisplay->height - y; + + /* Draw the filled rectangle */ + if(lcd_setWindow(x, y, x+w-1, y+h-1)) return; + +#define BUFFER_PIXELS 64 + int wh = w*h; + uint8 buffer[BUFFER_PIXELS * sizeof(uint8) * 3]; + for (int p = 0; p < wh; p += BUFFER_PIXELS) { + for(int pb = 0; pb < BUFFER_PIXELS; pb++) { + buffer[pb * 3 + 0] = r; + buffer[pb * 3 + 1] = g; + buffer[pb * 3 + 2] = b; + } + int rem = wh - p; + lcd_pushPixels(buffer, ((rem < BUFFER_PIXELS) ? rem : BUFFER_PIXELS)); + } +} + +void lcd_fillScreen(uint8 r, uint8 g, uint8 b) +{ + /* Fill the whole screen with one color */ + lcd_fillRect(0, 0, activeDisplay->width, activeDisplay->height, r, g, b); +} /* lcdst_drawScreen */ + +void lcd_pushChar(char c) +{ + char* bitmap = font8x8_basic[(unsigned int) c]; + int x,y; + int set; + int mask; + for (x=0; x < 8; x++) { + for (y=0; y < 8; y++) { + set = bitmap[x] & 1 << y; + printf("%c", set ? 'X' : ' '); + if (set) { + lcd_pushPx(200, 0, 0); + } else { + lcd_pushPx(0, 0, 0); + } + } + printf("\n"); + } +} + +void lcd_printChar(uint8 x, uint8 y, char c) +{ + lcd_setWindow(x, y, x+8 - 1, y+8 - 1); + lcd_pushChar(c); +} + +void lcd_printText(uint8 x, uint8 y, char* text) +{ + for (int i = 0; i < strlen(text); i++) { + lcd_printChar(x + i * 8, y, text[i]); + } +} + diff --git a/st7735.h b/st7735.h new file mode 100644 index 0000000..5211478 --- /dev/null +++ b/st7735.h @@ -0,0 +1,100 @@ +#ifndef uint8 +#define uint8 unsigned char +#endif + +typedef struct +{ + int cs, a0, rs; + uint8 width, height; +} lcd_t; + +/* + * Initialize the display and create a data structure for it. + * The last initialized display is active. + * + * Parameters: + * spiSpeed - Speed of the SPI interface. + * cs - Chip selection pin. + * a0 - Data/Command pin. + * rs - Optional reset pin. If you do not use it, enter -1. + * + * Return: Pointer to the structure with display data. + * + */ +lcd_t *lcd_init(int spiSpeed, int cs, int a0, int rs); + +/* + * Reset the specified display and clear the previously assigned memory. + * + * Parameters: + * display - Pointer to the structure with display data. + * + * Return: void + */ +void lcd_deinit(lcd_t *display); + +/* + * Set the drawing area on the currently active display. + * + * Parameters: + * x1 - The X parameter of the first point. + * y1 - The Y parameter of the first point. + * x2 - The X parameter of the second point. + * y2 - The Y parameter of the second point. + * + * Return: Confirmation of the occurrence or non-occurrence of an error. + * 0 - The error did not occur; 1 - The error occurred. + * + */ +uint8 lcd_setWindow(uint8 x1, uint8 y1, uint8 x2, uint8 y2); + +/* + * Draw one pixel on the currently active display. + * The color intensity scale for a normal pixel is from 0 to 255. + * The color intensity scale for the reduced pixel is from 0 to 15. + * + * Parameters: + * x - The X parameter of the pixel. + * y - The Y parameter of the pixel. + * r - The intensity of the red color. + * g - The intensity of the green color. + * b - The intensity of the blue color. + * + * Return: void + */ +void lcd_drawPx(uint8 x, uint8 y, uint8 r, uint8 g, uint8 b); + +/* + * Draw a filled rectangle on the currently active display. + * The color intensity scale for a normal pixel is from 0 to 255. + * The color intensity scale for the reduced pixel is from 0 to 15. + * + * Parameters: + * x - Parameter X of the upper left corner of the rectangle. + * y - Parameter Y of the upper left corner of the rectangle. + * w - The width of the rectangle. + * h - The height of the rectangle. + * r - The intensity of the red color. + * g - The intensity of the green color. + * b - The intensity of the blue color. + * + * Return: void + */ +void lcd_fillRect(uint8 x, uint8 y, uint8 w, uint8 h, uint8 r, uint8 g, uint8 b); + +/* + * Fill the entire screen with one color of the currently active display. + * The color intensity scale for a normal pixel is from 0 to 255. + * The color intensity scale for the reduced pixel is from 0 to 15. + * + * Parameters: + * r - The intensity of the red color. + * g - The intensity of the green color. + * b - The intensity of the blue color. + * + * Return: void + */ +void lcd_fillScreen(uint8 r, uint8 g, uint8 b); + +void lcd_printChar(uint8 x, uint8 y, char c); +void lcd_printText(uint8 x, uint8 y, char* text);