diff --git a/Makefile b/Makefile index 3cc1bd8..c581831 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,23 @@ PROGRAMMER_TYPE = avrispmkII PROGRAMMER_ARGS = +# These settings should be enough to get all currently supported +# drivers to work (they are very similar): +# - ST7735R +# - ST7789 +# - ILI9341 + +# Display dimensions +DISPLAY_WIDTH = 160 +DISPLAY_HEIGHT = 128 +# 1 = BGR, 0 = RGB +BGR = 0 +# Invert color +INVERT = 0 +# Flip image +HFLIP = 0 +VFLIP = 1 + MAIN = avrtft.c SRC = bitmaps.c bmp.c cmd.c display.c emojis.c tft.c font.c spi.c hack.c usart.c @@ -17,7 +34,9 @@ AVRSIZE = avr-size AVRDUDE = avrdude -CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -DBAUD=$(BAUD) +CFLAGS = -mmcu=$(MCU) -DF_CPU=$(F_CPU)UL -DBAUD=$(BAUD) +CFLAGS += -DDISPLAY_WIDTH=$(DISPLAY_WIDTH) -DDISPLAY_HEIGHT=$(DISPLAY_HEIGHT) +CFLAGS += -DINVERT=$(INVERT) -DBGR=$(BGR) -DHFLIP=$(HFLIP) -DVFLIP=$(VFLIP) CFLAGS += -O2 -I. CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums CFLAGS += -Wall -Wstrict-prototypes diff --git a/README.md b/README.md index 827bb1f..66fc423 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ # AVRTFT -Simple project to drive a TFT LCD like the -[Adafruit 1.8" Color TFT LCD 160x128 ST7735R](https://www.adafruit.com/product/358) -with an AVR MCU (ATmega328P) and avr-libc. +Simple project to drive a TFT LCD with an AVR MCU (ATmega328P) and avr-libc. -Currently implemented: +Currently supported displays/drivers: + +* [Adafruit 1.8" Color TFT LCD 160x128 ST7735R](https://www.adafruit.com/product/358) +* [Adafruit 2.0" Color IPS TFT 320x240 ST7789](https://www.adafruit.com/product/4311) +* [Adafruit 2.8" Color TFT LCD with Cap Touch 320x240 ILI9341](https://www.adafruit.com/product/2090) + +Currently implemented features: * Mostly complete UTF-8 set (code points U+0000 to U+00FF) of Hack font with antialiasing (4-Bit greyscale) @@ -19,6 +23,7 @@ Ideas: +* Support touch * Read pictures from SD Card * Display 4K@50Hz videos... diff --git a/bmp.c b/bmp.c index ded0f8d..dd3465a 100644 --- a/bmp.c +++ b/bmp.c @@ -32,7 +32,22 @@ // static uint16_t rowSize = 0; /** - * Pushes the given byte on the stack and the oldest off the stack. + * Resets the state. + */ +static void reset(void) { + offset = 0; + pixelStart = -1; + pixelEnd = -1; + // headerSize = 0; + bitmapWidth = 0; + bitmapHeight = 0; + bitsPerPixel = 0; + imageSize = 0; + // rowSize = 0; +} + +/** + * Pushes the given byte on the queue and the oldest off the queue. * * @param byte */ @@ -142,7 +157,7 @@ if (offset == pixelStart) { // do horizontal flip because pixel data in a BMP is bottom to top - setArea(row, col, bitmapWidth, bitmapHeight, true); + setArea(row, col, bitmapWidth, bitmapHeight, true, false); writeStart(); } @@ -160,6 +175,7 @@ if (offset == pixelEnd) { writeEnd(); + reset(); setStreamingData(false); // printString("write end\r\n"); } diff --git a/display.c b/display.c index a5ccb73..d1d1218 100644 --- a/display.c +++ b/display.c @@ -33,7 +33,7 @@ width_t writeBitmap(row_t row, col_t col, uint16_t index) { const __flash Bitmap *bitmap = &bitmaps[index]; - setArea(row, col, bitmap->width, bitmap->height, false); + setArea(row, col, bitmap->width, bitmap->height, false, false); writeData(bitmap->bitmap, bitmap->width, bitmap->height, bitmap->space); return bitmap->width; @@ -41,7 +41,7 @@ width_t writeGlyph(row_t row, col_t col, const __flash Font *font, code_t code) { const __flash Glyph *glyph = getGlyphAddress(font, code); - setArea(row, col, glyph->width, font->height, false); + setArea(row, col, glyph->width, font->height, false, false); writeData(glyph->bitmap, glyph->width, font->height, font->space); return glyph->width; diff --git a/emojis/emojis.sh b/emojis/emojis.sh index 00dfccb..2e627e7 100755 --- a/emojis/emojis.sh +++ b/emojis/emojis.sh @@ -5,7 +5,7 @@ # clear the display all black and write all the emojis... echo "c ffff" > /dev/ttyUSB0 -sleep 0.1 +sleep 1 echo -e "t 0 0 Hello Emojis!" > /dev/ttyUSB0 sleep 0.1 echo -e 't 16 0 \ts' > /dev/ttyUSB0 diff --git a/tft.c b/tft.c index c78da3e..fd75cb8 100644 --- a/tft.c +++ b/tft.c @@ -101,6 +101,12 @@ displayCmd(NORON); displayDes(); + // Display Inversion on/off + uint8_t inv = INVERT ? INVON : INVOFF; + displaySel(); + displayCmd(inv); + displayDes(); + // Interface pixel format displaySel(); displayCmd(COLMOD); @@ -151,8 +157,8 @@ displayCmd(RAMWR); displaySetData(); - bytes_t bytes = width * height; - for (uint16_t i = 0; i < bytes; i++) { + bytes_t pixels = (bytes_t)width * (bytes_t)height; + for (bytes_t i = 0; i < pixels; i++) { transmit(color >> 8); transmit(color); } @@ -162,13 +168,23 @@ void setArea(row_t row, col_t col, width_t width, height_t height, - bool hflip) { + bool hflip, bool vflip) { // Memory data access control - uint8_t madctl = 0b01110110; - if (hflip) { - madctl = 0b00110110; + uint8_t madctl = 0b11110110; + madctl &= ~(VFLIP << 7); + madctl &= ~(HFLIP << 6); + madctl |= (BGR << 3); + + if (vflip) { + // Row Address Order (MY) + madctl = madctl ^ (1 << 7); } + if (hflip) { + // Column Address Order (MX) + madctl = madctl ^ (1 << 6); + } + displaySel(); displayCmd(MADCTL); displayData(madctl); @@ -177,6 +193,10 @@ // X address start/end uint16_t xs = col; uint16_t xe = col + width - 1; + if (vflip) { + xs = DISPLAY_WIDTH - col - width; + xe = DISPLAY_WIDTH - col - 1; + } displaySel(); displayCmd(CASET); displayData(xs >> 8); @@ -189,8 +209,8 @@ uint16_t ys = row; uint16_t ye = row + height - 1; if (hflip) { - xs = DISPLAY_HEIGHT - row - height; - xe = DISPLAY_HEIGHT - row - 1; + ys = DISPLAY_HEIGHT - row - height; + ye = DISPLAY_HEIGHT - row - 1; } displaySel(); displayCmd(RASET); @@ -210,8 +230,8 @@ displaySetData(); if (space == SPACE_GREY4) { - bytes_t bytes = width * height / 2; - for (uint16_t i = 0; i < bytes; i++) { + bytes_t bytes = (bytes_t)width * (bytes_t)height / 2; + for (bytes_t i = 0; i < bytes; i++) { uint8_t rgb[4]; grey4ToRGB16(bitmap[i], rgb); for (uint8_t j = 0; j < 4; j++) { @@ -220,8 +240,8 @@ } } else { // SPACE_RGB16 - bytes_t bytes = width * height * 2; - for (uint16_t i = 0; i < bytes; i++) { + bytes_t bytes = (bytes_t)width * (bytes_t)height * 2; + for (bytes_t i = 0; i < bytes; i++) { transmit(bitmap[i]); } } diff --git a/tft.h b/tft.h index c5b6c0d..ddfbca8 100644 --- a/tft.h +++ b/tft.h @@ -15,6 +15,8 @@ #define SLPIN 0x10 #define SLPOUT 0x11 #define NORON 0x13 +#define INVOFF 0x20 +#define INVON 0x21 #define DISPON 0x29 #define CASET 0x2a #define RASET 0x2b @@ -22,8 +24,29 @@ #define MADCTL 0x36 #define COLMOD 0x3a -#define DISPLAY_WIDTH 160 -#define DISPLAY_HEIGHT 128 +#ifndef DISPLAY_WIDTH + #define DISPLAY_WIDTH 160 +#endif + +#ifndef DISPLAY_HEIGHT + #define DISPLAY_HEIGHT 128 +#endif + +#ifndef BGR + #define BGR 0 +#endif + +#ifndef INVERT + #define INVERT 0 +#endif + +#ifndef HFLIP + #define HFLIP 0 +#endif + +#ifndef VFLIP + #define VFLIP 0 +#endif // TODO use enum? typedef? #define SPACE_GREY4 4 @@ -77,10 +100,11 @@ * @param width width of the bitmap in pixels * @param height height of the bitmap in pixels * @param hflip if image should be flipped horizontally + * @param vflip if image should be flipped vertically */ void setArea(row_t row, col_t col, width_t width, height_t height, - bool hflip); + bool hflip, bool vflip); /** * Writes image data to the previously set area. diff --git a/types.h b/types.h index 84bf9b0..bc3b920 100644 --- a/types.h +++ b/types.h @@ -9,16 +9,16 @@ #define TYPES_H /* Width, height and color space of bitmaps and glyphs */ -typedef uint8_t width_t; -typedef uint8_t height_t; +typedef uint16_t width_t; +typedef uint16_t height_t; typedef uint8_t space_t; /* Width * height * bytes per pixel */ -typedef uint16_t bytes_t; +typedef uint32_t bytes_t; /* Number of rows and columns of the display */ -typedef uint8_t row_t; -typedef uint8_t col_t; +typedef uint16_t row_t; +typedef uint16_t col_t; /* Char code (like UTF-8 code point) */ typedef uint8_t code_t;