diff --git a/Makefile b/Makefile index c581831..39272bb 100644 --- a/Makefile +++ b/Makefile @@ -15,18 +15,19 @@ # - ILI9341 # Display dimensions -DISPLAY_WIDTH = 160 -DISPLAY_HEIGHT = 128 +DISPLAY_WIDTH = 320 +DISPLAY_HEIGHT = 240 # 1 = BGR, 0 = RGB -BGR = 0 +BGR = 1 # Invert color INVERT = 0 # Flip image -HFLIP = 0 +HFLIP = 1 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 +SRC = bitmaps.c bmp.c cmd.c display.c emojis.c i2c.c paint.c tft.c touch.c \ + font.c spi.c hack.c usart.c CC = avr-gcc OBJCOPY = avr-objcopy @@ -52,8 +53,9 @@ OBJ = $(SRC:.c=.o) OBJ = $(SRC:.S=.o) -$(TARGET).elf: bitmaps.h bmp.h cmd.h display.h emojis.h tft.h font.h pins.h \ - spi.h types.h hack.h usart.h utils.h Makefile +$(TARGET).elf: bitmaps.h bmp.h cmd.h display.h emojis.h i2c.h paint.h tft.h \ + touch.h font.h pins.h spi.h types.h hack.h usart.h utils.h \ + Makefile all: $(TARGET).hex diff --git a/README.md b/README.md index 66fc423..f16da4e 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,17 @@ * Draw bitmaps * Write text and bitmaps via USART * Upload BMP images via USART (16-Bit 5/6/5 RGB) -* Logging via USART +* Process touch events (FT6206) +* Very basic paint application +* Logging via USART -The AVR is clocked with a crystal for reliable communication via USART. +The AVR is clocked with a crystal for reliable communication via USART. + +RAM usage currently is 210 bytes. Program memory is fully used, mainly by +font and emoji bitmaps. Ideas: -* Support touch * Read pictures from SD Card * Display 4K@50Hz videos... @@ -39,10 +43,26 @@ `t 0 0 Just some text` // write text in Hack to row 0 column 0 `b 0 0 1` // write bitmap with index 1 (tiny Linus cat) to row 0 column 0 `p 0 0` // prepare to "stream" a 16-Bit (5/6/5) RGB BMP image to row 0 column 0 -`cat Bali160x128.bmp > /dev/ttyUSB0` // upload a "fullscreen" BMP image +`cat Bali160x128.bmp > /dev/ttyUSB0` // upload a BMP image ## Enter emojis Emojis are entered with a tabulation char + their "code", i.e. `Smile!s` for a smiling emoji. ![IMG_20231129_004922](https://github.com/gitdode/avrtft/assets/11530253/3a6cbcdd-d004-48d9-a227-ba21f91dac0b) + +## Paint application + +A super basic paint application created to learn about processing touch events +and draw something on the screen. + +The FT6206 based touch screen of the +[Adafruit 2.8" Color TFT LCD with Cap Touch 320x240 ILI9341](https://www.adafruit.com/product/2090) +works quite well but at least for me the coordinates of touches close to the +long edges of the screen are a bit off (too close to the edge) and there seems +to be no calibration capability - the data sheet mentions "auto calibration". + +But still it is fun and it should be possible to create an application +supporting touch with reliable usability. + +![IMG_20240103_134738](https://github.com/gitdode/avrtft/assets/11530253/5e9947cc-e236-49e7-a06b-1dbfffa304b7) diff --git a/avrtft.c b/avrtft.c index 6541487..916a506 100644 --- a/avrtft.c +++ b/avrtft.c @@ -30,15 +30,15 @@ #include "display.h" #include "utils.h" #include "bmp.h" - -/* Timer0 interrupts per second */ -#define INTS_SEC F_CPU / (256UL * 255) +#include "touch.h" +#include "paint.h" static bool once = false; static volatile uint16_t ints = 0; +static volatile bool touch = false; -ISR(TIMER0_COMPA_vect) { - ints++; +ISR(INT0_vect) { + touch = true; } /** @@ -52,6 +52,10 @@ PORT_SPI |= (1 << PIN_SS); PORT_SPI |= (1 << PIN_MISO); + // set SDA and SCL as output pin + // DDR_I2C |= (1 << PIN_SCL); + // DDR_I2C |= (1 << PIN_SDA); + // set display CS, D/C and RST pin as output pin DDR_DSPI |= (1 << PIN_DCS); DDR_DSPI |= (1 << PIN_DC); @@ -74,17 +78,22 @@ } /** - * Sets up the timer. + * Enables I2C. */ -static void initTimer(void) { - // timer0 clear timer on compare match mode, TOP OCR0A - TCCR0A |= (1 << WGM01); - // timer0 clock prescaler/256/255 ~ 123 Hz @ 8 MHz - TCCR0B |= (1 << CS02); - OCR0A = 255; +static void initI2C(void) { + // 100 kHz @ 16 Mhz + TWBR = 72; + TWCR |= (1 << TWEN); +} - // enable timer0 compare match A interrupt - // TIMSK0 |= (1 << OCIE0A); +/** + * Enables touch interrupt. + */ +static void initTouchInt(void) { + EIMSK |= (1 << INT0); + // EICRA |= (1 << ISC00); // interrupt on any logical change + EICRA |= (1 << ISC01); // interrupt on falling edge + // EICRA |= (1 << ISC01) | (1 << ISC00); // interrupt on rising edge } int main(void) { @@ -92,23 +101,37 @@ initUSART(); initPins(); initSPI(); - initTimer(); + initI2C(); // enable global interrupts sei(); - + _delay_ms(1000); + initDisplay(); + initTouchInt(); + + // ignore initial touch interrupt + _delay_ms(1); + touch = false; while (true) { - + // show a demo once at the start if (!once) { - // setFrame(0x0); - hackDemo(); + initPaint(); + // hackDemo(); once = true; } + if (touch) { + touch = false; + Point point = {0}; + // memset(&point, 0, sizeof (Point)); + uint8_t event = readTouch(&point); + paintEvent(event, &point); + } + if (isStreamingData()) { char data = UDR0; stream(data); diff --git a/bitmaps.c b/bitmaps.c index 2678aab..6956228 100644 --- a/bitmaps.c +++ b/bitmaps.c @@ -10,143 +10,53 @@ #include "tft.h" #include "utils.h" -const __flash uint8_t LINUS_GREY4_DATA[] = { - 0xff, 0xfe, 0xee, 0xcd, 0xed, 0xdc, 0xcc, 0xbb, 0xbc, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xee, 0xcd, 0xed, 0xdc, 0xcc, 0xbb, 0xbc, 0xd6, 0x6f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xee, 0xcd, 0xed, 0xdc, 0xcc, 0xbb, 0xbc, 0x81, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xee, 0x96, 0xcd, 0xdc, 0xcc, 0xbb, 0xbb, 0x31, 0x16, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xee, 0xa2, 0x4a, 0xdc, 0xcc, 0xbb, 0xb9, 0x11, 0x11, 0xef, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xee, 0xc3, 0x34, 0x8c, 0xcb, 0xbb, 0xa4, 0x11, 0x21, 0xcf, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xee, 0xde, 0xc7, 0x24, 0x34, 0x68, 0x97, 0x40, 0x11, 0x11, 0xaf, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0xdd, 0xce, 0xca, 0x24, 0x31, 0x13, 0x33, 0x10, 0x10, 0x00, 0x5e, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xed, 0xcd, 0xcb, 0x71, 0x40, 0x11, 0x13, 0x11, 0x10, 0x00, 0x2b, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xdd, 0xcc, 0x93, 0x31, 0x01, 0x13, 0x00, 0x11, 0x00, 0x19, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0xdd, 0xcb, 0xa4, 0x41, 0x01, 0x12, 0x00, 0x11, 0x00, 0x14, 0xef, 0xff, 0xff, 0xff, - 0xff, 0xee, 0xdd, 0xdb, 0xa3, 0x20, 0x00, 0x00, 0x21, 0x01, 0x10, 0x12, 0xbf, 0xff, 0xff, 0xff, - 0xee, 0xed, 0xcd, 0xdb, 0x61, 0x30, 0x00, 0x04, 0x65, 0x00, 0x00, 0x11, 0x8f, 0xff, 0xff, 0xff, - 0xef, 0xee, 0xcd, 0xda, 0x22, 0x64, 0x10, 0x03, 0x51, 0x00, 0x00, 0x01, 0x4d, 0xff, 0xff, 0xff, - 0xee, 0xed, 0xcc, 0xda, 0x21, 0x32, 0x11, 0x00, 0x00, 0x00, 0x01, 0x01, 0x38, 0xff, 0xff, 0xff, - 0xef, 0xed, 0xcc, 0xd9, 0x21, 0x01, 0x41, 0x00, 0x00, 0x00, 0x00, 0x12, 0x44, 0xbf, 0xff, 0xff, - 0xee, 0xed, 0xcc, 0xca, 0x31, 0x13, 0x31, 0x00, 0x01, 0x22, 0x22, 0x10, 0x33, 0x7e, 0xff, 0xff, - 0xef, 0xed, 0xcc, 0xcb, 0x51, 0x21, 0x10, 0x00, 0x12, 0x43, 0x23, 0x32, 0x22, 0x5d, 0xff, 0xff, - 0xee, 0xed, 0xcc, 0xcb, 0x94, 0x42, 0x14, 0x10, 0x14, 0x54, 0x33, 0x34, 0x33, 0x4a, 0xef, 0xff, - 0xff, 0xed, 0xcb, 0xcb, 0xb8, 0x64, 0x41, 0x01, 0x23, 0x43, 0x44, 0x44, 0x42, 0x38, 0xee, 0xff, - 0xff, 0xfd, 0xcb, 0xcb, 0xb8, 0x55, 0x65, 0x11, 0x13, 0x56, 0x78, 0x95, 0x32, 0x37, 0xde, 0xee, - 0xff, 0xed, 0xcb, 0xcb, 0xb7, 0x58, 0x66, 0x65, 0x67, 0x89, 0x9a, 0x83, 0x43, 0x26, 0xde, 0xee, - 0xee, 0xcc, 0xcb, 0xbb, 0xb6, 0x58, 0x98, 0x88, 0x88, 0x99, 0xaa, 0x71, 0x13, 0x36, 0xce, 0xed, - 0xdc, 0xcc, 0xbb, 0xbb, 0xb8, 0x99, 0x99, 0x98, 0x99, 0x99, 0x99, 0x72, 0x21, 0x25, 0x8c, 0xdd, - 0xcc, 0xcc, 0xbb, 0xbb, 0xb8, 0x79, 0x99, 0x99, 0x99, 0x99, 0xa8, 0x51, 0x11, 0x35, 0x47, 0xcc, - 0xcc, 0xbb, 0xba, 0xbb, 0xa9, 0x57, 0x88, 0x99, 0x99, 0x99, 0x73, 0x01, 0x01, 0x35, 0x33, 0x8c +const __flash uint8_t FREE_DATA[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x10, 0x20, 0x20, 0x10, 0x27, 0x10, 0x44, 0x88, + 0x4c, 0x88, 0x48, 0x88, 0x48, 0x88, 0x2b, 0x08, + 0x1c, 0x10, 0x03, 0xe0, 0x00, 0x00, 0x00, 0x00 }; -const __flash uint8_t LINUS_RGB16_DATA[] = { - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xdd, 0xf7, 0x7b, 0xef, 0x5a, 0xef, 0x18, 0xde, 0x76, 0xe6, 0xf7, - 0xef, 0x18, 0xee, 0xf7, 0xee, 0xd7, 0xe6, 0x75, 0xde, 0x34, 0xd6, 0x14, 0xd5, 0xf3, 0xcd, 0xb2, - 0xcd, 0xd3, 0xe6, 0x75, 0xf7, 0x38, 0xff, 0x9a, 0xff, 0xbb, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xdc, 0xef, 0x7a, 0xef, 0x59, 0xef, 0x39, 0xde, 0x76, 0xe6, 0xd7, - 0xef, 0x17, 0xee, 0xf7, 0xee, 0xd7, 0xe6, 0x75, 0xde, 0x34, 0xd6, 0x14, 0xd5, 0xf3, 0xcd, 0xb2, - 0xcd, 0xd3, 0xde, 0x55, 0xe6, 0xb6, 0x73, 0x4b, 0x73, 0x6b, 0xf7, 0xbc, 0xff, 0xfe, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfd, 0xff, 0xdc, 0xf7, 0x7a, 0xef, 0x39, 0xef, 0x38, 0xd6, 0x55, 0xe6, 0xb7, - 0xef, 0x18, 0xee, 0xf7, 0xee, 0xd7, 0xe6, 0x75, 0xde, 0x34, 0xd6, 0x14, 0xd5, 0xf3, 0xcd, 0xb2, - 0xcd, 0xb3, 0xde, 0x34, 0x9c, 0x6f, 0x30, 0xe2, 0x39, 0x02, 0xc5, 0xf5, 0xff, 0xfe, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xfd, 0xf7, 0xbc, 0xf7, 0x7a, 0xef, 0x39, 0xef, 0x38, 0xac, 0xf1, 0x7b, 0x8c, - 0xd6, 0x55, 0xee, 0xf7, 0xe6, 0xd7, 0xe6, 0x75, 0xde, 0x34, 0xd6, 0x14, 0xd5, 0xd3, 0xcd, 0xb2, - 0xc5, 0xb2, 0xcd, 0xd3, 0x4a, 0x07, 0x28, 0xe3, 0x31, 0x03, 0x73, 0x2b, 0xff, 0xdd, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xff, 0xff, 0xdd, 0xf7, 0xbc, 0xf7, 0x7a, 0xef, 0x39, 0xef, 0x39, 0xb5, 0x31, 0x41, 0x44, - 0x5a, 0x89, 0xb5, 0x73, 0xe6, 0xb6, 0xe6, 0x75, 0xde, 0x34, 0xd6, 0x14, 0xd5, 0xf3, 0xcd, 0xb2, - 0xc5, 0x92, 0xa4, 0xaf, 0x31, 0x44, 0x29, 0x04, 0x29, 0x03, 0x31, 0x03, 0xe7, 0x1a, 0xff, 0xfe, - 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf7, 0xdc, 0xf7, 0x9b, 0xf7, 0x7a, 0xef, 0x39, 0xef, 0x18, 0xd6, 0x35, 0x51, 0xc5, - 0x49, 0xc5, 0x5a, 0xaa, 0x94, 0x70, 0xd6, 0x15, 0xde, 0x14, 0xd5, 0xf3, 0xd5, 0xf3, 0xcd, 0xb2, - 0xbd, 0x72, 0x5a, 0x88, 0x29, 0x24, 0x31, 0x24, 0x39, 0x44, 0x31, 0x23, 0xd6, 0x77, 0xff, 0xfd, - 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xdd, 0xf7, 0x9b, 0xef, 0x7a, 0xef, 0x59, 0xe7, 0x18, 0xef, 0x18, 0xde, 0x76, 0x8b, 0xcd, - 0x49, 0x43, 0x62, 0xaa, 0x41, 0xe7, 0x52, 0xaa, 0x7b, 0x8d, 0x94, 0x91, 0xa4, 0xf2, 0x84, 0x0f, - 0x5a, 0xaa, 0x18, 0xc2, 0x28, 0xe3, 0x28, 0xe3, 0x31, 0x03, 0x31, 0x03, 0xad, 0x32, 0xff, 0xfd, - 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xf7, 0xbc, 0xe7, 0x5a, 0xe7, 0x19, 0xde, 0xb7, 0xde, 0x96, 0xef, 0x18, 0xde, 0x76, 0xbd, 0x92, - 0x49, 0xa5, 0x5a, 0x48, 0x4a, 0x07, 0x20, 0xe4, 0x29, 0x24, 0x39, 0xe8, 0x39, 0xe7, 0x39, 0xe7, - 0x21, 0x24, 0x18, 0xc3, 0x20, 0xe3, 0x20, 0xc2, 0x18, 0xa2, 0x20, 0xc3, 0x62, 0xea, 0xf7, 0x7b, - 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, - 0xff, 0xfe, 0xf7, 0xbc, 0xef, 0x9b, 0xe6, 0xf9, 0xde, 0x76, 0xe6, 0xf8, 0xde, 0x76, 0xd5, 0xf4, - 0x8b, 0xcc, 0x31, 0x24, 0x52, 0x89, 0x18, 0xc3, 0x20, 0xe3, 0x21, 0x04, 0x21, 0x04, 0x39, 0xe7, - 0x21, 0x04, 0x21, 0x04, 0x21, 0x04, 0x20, 0xc3, 0x10, 0x82, 0x10, 0x82, 0x31, 0x65, 0xc5, 0xd5, - 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, - 0xf7, 0xbc, 0xf7, 0xbb, 0xf7, 0xbb, 0xe7, 0x39, 0xde, 0x97, 0xe6, 0xf8, 0xde, 0x96, 0xd6, 0x14, - 0xa4, 0xd0, 0x41, 0xe6, 0x4a, 0x48, 0x21, 0x04, 0x20, 0xc3, 0x20, 0xe4, 0x21, 0x04, 0x39, 0xe8, - 0x18, 0xc3, 0x18, 0xa2, 0x20, 0xe3, 0x21, 0x04, 0x18, 0xc3, 0x10, 0x82, 0x21, 0x24, 0xa4, 0xb0, - 0xff, 0xdd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, - 0xf7, 0xbc, 0xf7, 0x9b, 0xf7, 0x9b, 0xef, 0x5a, 0xde, 0xd7, 0xe7, 0x18, 0xde, 0x96, 0xcd, 0xf4, - 0xb5, 0x52, 0x5a, 0xa9, 0x52, 0x68, 0x29, 0x44, 0x18, 0xc3, 0x20, 0xe4, 0x21, 0x04, 0x31, 0x86, - 0x18, 0xc3, 0x18, 0xa3, 0x20, 0xe3, 0x21, 0x04, 0x18, 0xc3, 0x18, 0xc3, 0x20, 0xe4, 0x5a, 0x68, - 0xf7, 0x5a, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, - 0xf7, 0x9b, 0xf7, 0x9b, 0xf7, 0x7b, 0xef, 0x39, 0xde, 0xb7, 0xe7, 0x18, 0xde, 0xb6, 0xcd, 0xf3, - 0xb5, 0x11, 0x4a, 0x27, 0x31, 0x65, 0x18, 0xa2, 0x10, 0x82, 0x10, 0xa2, 0x10, 0xa2, 0x18, 0xc3, - 0x39, 0x84, 0x29, 0x24, 0x18, 0xc3, 0x20, 0xe3, 0x20, 0xe4, 0x18, 0xc3, 0x29, 0x24, 0x39, 0x86, - 0xc5, 0xf4, 0xff, 0xfd, 0xff, 0xdd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, - 0xef, 0x7b, 0xf7, 0x7a, 0xef, 0x5a, 0xe7, 0x18, 0xde, 0x96, 0xe6, 0xf7, 0xe6, 0xb7, 0xcd, 0xb3, - 0x7b, 0x6b, 0x31, 0x44, 0x41, 0xe6, 0x18, 0xc3, 0x18, 0xc3, 0x18, 0xa2, 0x10, 0x82, 0x52, 0x46, - 0x73, 0x6a, 0x6a, 0xe9, 0x18, 0xa2, 0x18, 0xa2, 0x10, 0xa2, 0x18, 0xc3, 0x21, 0x04, 0x29, 0x45, - 0x94, 0x2e, 0xff, 0xbb, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xdd, 0xff, 0xdd, 0xff, 0xfd, 0xff, 0xfd, - 0xef, 0x7b, 0xf7, 0x9b, 0xef, 0x7a, 0xef, 0x39, 0xde, 0x96, 0xe6, 0xd7, 0xe6, 0xd7, 0xb5, 0x51, - 0x39, 0x85, 0x39, 0xa5, 0x6b, 0x4a, 0x5a, 0xa8, 0x20, 0xe3, 0x18, 0xe3, 0x18, 0xc2, 0x4a, 0x47, - 0x62, 0xc8, 0x31, 0x44, 0x10, 0x82, 0x10, 0xa2, 0x18, 0xa2, 0x10, 0xa2, 0x18, 0xe3, 0x21, 0x04, - 0x52, 0x69, 0xe6, 0xd8, 0xff, 0xdc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xdd, - 0xef, 0x5a, 0xef, 0x5a, 0xef, 0x5a, 0xe6, 0xf8, 0xde, 0x76, 0xde, 0x96, 0xe6, 0xb6, 0xb5, 0x11, - 0x39, 0xa5, 0x20, 0xe3, 0x49, 0xe5, 0x39, 0xa5, 0x21, 0x04, 0x20, 0xe4, 0x18, 0xc3, 0x18, 0xa2, - 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x10, 0x82, 0x18, 0xc3, 0x21, 0x04, 0x18, 0xa3, 0x20, 0xe4, - 0x4a, 0x49, 0x9c, 0x90, 0xf7, 0x9b, 0xff, 0xdc, 0xff, 0xfc, 0xff, 0xfd, 0xff, 0xfd, 0xff, 0xfd, - 0xf7, 0x7b, 0xf7, 0x9b, 0xef, 0x7a, 0xe7, 0x18, 0xde, 0x96, 0xde, 0x76, 0xe6, 0x96, 0xac, 0xf0, - 0x39, 0x85, 0x20, 0xe3, 0x18, 0xc3, 0x29, 0x44, 0x52, 0x89, 0x21, 0x45, 0x18, 0xa3, 0x10, 0x82, - 0x10, 0x82, 0x10, 0x62, 0x10, 0x82, 0x10, 0x62, 0x10, 0x82, 0x18, 0xe3, 0x29, 0x45, 0x31, 0xa7, - 0x4a, 0x69, 0x52, 0x8a, 0xc5, 0xf5, 0xff, 0xbb, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xfc, - 0xef, 0x5a, 0xf7, 0x7a, 0xef, 0x5a, 0xe6, 0xd8, 0xd6, 0x55, 0xd6, 0x35, 0xde, 0x76, 0xbd, 0x72, - 0x52, 0x27, 0x31, 0x44, 0x20, 0xe3, 0x42, 0x07, 0x41, 0xe7, 0x21, 0x25, 0x18, 0xa2, 0x18, 0xa2, - 0x18, 0xc3, 0x21, 0x45, 0x29, 0x86, 0x29, 0x65, 0x31, 0x86, 0x29, 0x65, 0x21, 0x04, 0x18, 0xe3, - 0x39, 0xe8, 0x42, 0x28, 0x8c, 0x0f, 0xf7, 0x7a, 0xff, 0xdb, 0xff, 0xdc, 0xff, 0xdc, 0xff, 0xdc, - 0xf7, 0x7b, 0xf7, 0x9b, 0xef, 0x7a, 0xe6, 0xf8, 0xde, 0x76, 0xd6, 0x35, 0xde, 0x76, 0xcd, 0xb3, - 0x73, 0x2a, 0x29, 0x24, 0x39, 0xa6, 0x29, 0x44, 0x21, 0x04, 0x18, 0xc3, 0x10, 0xa2, 0x10, 0xa2, - 0x21, 0x24, 0x31, 0xa7, 0x4a, 0x6a, 0x42, 0x49, 0x31, 0xc7, 0x3a, 0x08, 0x3a, 0x09, 0x31, 0xc7, - 0x31, 0xc7, 0x39, 0xa7, 0x5a, 0xeb, 0xe6, 0xb7, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xbb, 0xff, 0xdb, - 0xef, 0x59, 0xf7, 0x9a, 0xef, 0x5a, 0xde, 0xd7, 0xd6, 0x55, 0xd6, 0x14, 0xde, 0x55, 0xcd, 0xd3, - 0xa4, 0xaf, 0x52, 0x68, 0x5a, 0x89, 0x31, 0x65, 0x21, 0x04, 0x4a, 0x69, 0x29, 0x45, 0x18, 0xc3, - 0x21, 0x24, 0x4a, 0x8a, 0x5a, 0xec, 0x52, 0xcb, 0x42, 0x49, 0x39, 0xe8, 0x39, 0xe8, 0x4a, 0xab, - 0x42, 0x29, 0x42, 0x29, 0x52, 0xcb, 0xb5, 0x74, 0xff, 0x7a, 0xff, 0x9b, 0xff, 0x9b, 0xff, 0x9b, - 0xff, 0xbb, 0xff, 0xfd, 0xef, 0x9b, 0xe6, 0xd8, 0xd6, 0x56, 0xcd, 0xf4, 0xde, 0x35, 0xcd, 0xd3, - 0xc5, 0x92, 0x94, 0x2e, 0x6b, 0x4c, 0x5a, 0xa9, 0x5a, 0x89, 0x29, 0x44, 0x18, 0xe3, 0x18, 0xe4, - 0x31, 0xc7, 0x42, 0x49, 0x4a, 0x6a, 0x42, 0x29, 0x52, 0xcb, 0x52, 0xab, 0x4a, 0xac, 0x4a, 0x8b, - 0x42, 0x6a, 0x31, 0xc7, 0x39, 0xe8, 0x94, 0x71, 0xf7, 0x59, 0xff, 0x7a, 0xff, 0x9a, 0xff, 0x9a, - 0xff, 0xbc, 0xff, 0xfd, 0xf7, 0x9c, 0xe6, 0xf8, 0xd6, 0x56, 0xcd, 0xd3, 0xd6, 0x35, 0xcd, 0xf4, - 0xc5, 0xb3, 0x94, 0x6f, 0x6b, 0x0a, 0x62, 0xea, 0x7b, 0xad, 0x6b, 0x2b, 0x29, 0x23, 0x21, 0x03, - 0x29, 0x24, 0x42, 0x08, 0x63, 0x0c, 0x6b, 0x8e, 0x84, 0x30, 0x8c, 0xb3, 0x8c, 0xd4, 0x53, 0x0d, - 0x31, 0xe8, 0x31, 0x86, 0x39, 0xe8, 0x7b, 0xcf, 0xee, 0xf8, 0xf7, 0x59, 0xf7, 0x79, 0xf7, 0x59, - 0xff, 0xdc, 0xff, 0xdc, 0xef, 0x7b, 0xe6, 0xd7, 0xd6, 0x35, 0xc5, 0xb2, 0xd6, 0x34, 0xcd, 0xd3, - 0xc5, 0xb3, 0x8b, 0xed, 0x62, 0xea, 0x8c, 0x4f, 0x7b, 0xad, 0x73, 0x8d, 0x73, 0x6c, 0x62, 0xca, - 0x73, 0x6c, 0x84, 0x0f, 0x8c, 0x71, 0x9c, 0xd3, 0x9d, 0x14, 0xa5, 0x76, 0x84, 0x93, 0x31, 0xe8, - 0x42, 0x6a, 0x42, 0x29, 0x31, 0xa7, 0x73, 0x8d, 0xe6, 0xd7, 0xf7, 0x38, 0xf7, 0x39, 0xf7, 0x38, - 0xef, 0x18, 0xef, 0x18, 0xde, 0x96, 0xd6, 0x55, 0xd6, 0x15, 0xc5, 0xb3, 0xd5, 0xf4, 0xcd, 0xf3, - 0xc5, 0xb3, 0x83, 0x8c, 0x62, 0xea, 0x94, 0xb1, 0x9c, 0xd1, 0x94, 0x90, 0x94, 0x70, 0x94, 0x70, - 0x94, 0x90, 0x94, 0xb1, 0x9c, 0xd2, 0xa5, 0x13, 0xa5, 0x55, 0xa5, 0x55, 0x73, 0xf0, 0x21, 0x45, - 0x21, 0x25, 0x42, 0x29, 0x39, 0xe8, 0x73, 0xaf, 0xd6, 0x76, 0xef, 0x18, 0xef, 0x18, 0xee, 0xf8, - 0xde, 0xb7, 0xde, 0x76, 0xd6, 0x35, 0xd6, 0x14, 0xcd, 0xf4, 0xc5, 0x92, 0xcd, 0xf3, 0xcd, 0xf4, - 0xc5, 0x92, 0x9c, 0x90, 0x9c, 0xb1, 0x9c, 0xb1, 0x9c, 0xd1, 0x9c, 0xd1, 0x9c, 0xb1, 0x94, 0xb1, - 0x9c, 0xb1, 0x9c, 0xf2, 0x9c, 0xf2, 0xa5, 0x13, 0xa5, 0x13, 0x94, 0xd2, 0x7b, 0xcf, 0x31, 0xc7, - 0x29, 0x66, 0x21, 0x24, 0x39, 0xc7, 0x63, 0x2d, 0x8c, 0x51, 0xd6, 0x56, 0xe6, 0xd7, 0xe6, 0xb7, - 0xd6, 0x56, 0xd6, 0x56, 0xd6, 0x35, 0xd6, 0x35, 0xce, 0x14, 0xc5, 0x92, 0xcd, 0xd3, 0xcd, 0xd3, - 0xc5, 0x92, 0x94, 0x4e, 0x84, 0x0f, 0x9c, 0xd1, 0x9c, 0xd1, 0x9c, 0xd1, 0x9c, 0xd1, 0x9c, 0xd1, - 0x9c, 0xd1, 0x9c, 0xf2, 0x9d, 0x12, 0xa5, 0x13, 0xa5, 0x34, 0x84, 0x51, 0x5a, 0xec, 0x21, 0x25, - 0x18, 0xe4, 0x21, 0x04, 0x39, 0xe8, 0x5b, 0x2e, 0x52, 0xab, 0x84, 0x0f, 0xd6, 0x35, 0xde, 0x76, - 0xd6, 0x35, 0xce, 0x15, 0xcd, 0xf4, 0xcd, 0xf4, 0xc5, 0xd3, 0xbd, 0x51, 0xc5, 0xb2, 0xcd, 0xd3, - 0xc5, 0x72, 0xac, 0xcf, 0x62, 0xc9, 0x7b, 0xce, 0x8c, 0x50, 0x94, 0xb0, 0x9c, 0xd1, 0x9c, 0xd1, - 0x9c, 0xd1, 0xa4, 0xf2, 0x9c, 0xf2, 0x9c, 0xd2, 0x84, 0x30, 0x42, 0x49, 0x18, 0xc3, 0x18, 0xe4, - 0x18, 0xe3, 0x29, 0x24, 0x42, 0x29, 0x52, 0xed, 0x3a, 0x09, 0x4a, 0x49, 0x8c, 0x4f, 0xce, 0x15 +const __flash uint8_t LINE_DATA[] = { + 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x18, + 0x00, 0x30, 0x00, 0x60, 0x00, 0xc0, 0x01, 0x80, + 0x03, 0x00, 0x06, 0x00, 0x0c, 0x00, 0x18, 0x00, + 0x30, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const __flash uint8_t RECT_DATA[] = { + 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x20, 0x04, + 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, + 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x04, + 0x20, 0x04, 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00 +}; + +const __flash uint8_t ERASER_DATA[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1f, 0xfe, 0x10, 0x7e, 0x20, 0xfc, + 0x20, 0xfc, 0x20, 0xfc, 0x41, 0xf8, 0x7f, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const __flash uint8_t THICK_DATA[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfc, 0x3f, 0xfc, + 0x3f, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const __flash uint8_t CLEAR_DATA[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; const __flash Bitmap bitmaps[] = { - {32, 26, SPACE_GREY4, LINUS_GREY4_DATA}, - {32, 26, SPACE_RGB16, LINUS_RGB16_DATA} + {16, 16, SPACE_MONO1, FREE_DATA}, + {16, 16, SPACE_MONO1, LINE_DATA}, + {16, 16, SPACE_MONO1, RECT_DATA}, + {16, 16, SPACE_MONO1, ERASER_DATA}, + {16, 16, SPACE_MONO1, THICK_DATA}, + {16, 16, SPACE_MONO1, CLEAR_DATA} }; diff --git a/bitmaps.h b/bitmaps.h index 64479ba..29f5cbe 100644 --- a/bitmaps.h +++ b/bitmaps.h @@ -11,16 +11,20 @@ #include #include "types.h" -#define LINUS_GREY4 0 -#define LINUS_RGB16 1 +#define FREE 0 +#define LINE 1 +#define RECT 2 +#define ERASER 3 +#define THICK 4 +#define CLEAR 5 /** * A bitmap with its width and height, and data. */ typedef struct { - /** Width of the bitmap, must be a multiple of 8. */ + /** Width of the bitmap. */ const width_t width; - /** Height of the bitmap, must be a multiple of 8. */ + /** Height of the bitmap. */ const height_t height; /** Color space of the bitmap. */ const space_t space; diff --git a/bmp.c b/bmp.c index dd3465a..bfc3ce0 100644 --- a/bmp.c +++ b/bmp.c @@ -1,6 +1,6 @@ /* * File: bmp.h - * Author: dode + * Author: torsten.roemer@luniks.net * * Thanks to https://en.wikipedia.org/wiki/BMP_file_format * diff --git a/bmp.h b/bmp.h index b81d5a0..c7a7875 100644 --- a/bmp.h +++ b/bmp.h @@ -1,6 +1,6 @@ /* * File: bmp.h - * Author: dode + * Author: torsten.roemer@luniks.net * * Created on 22. November 2023, 23:10 */ diff --git a/cmd.c b/cmd.c index 2da4593..dcbfbee 100644 --- a/cmd.c +++ b/cmd.c @@ -15,6 +15,7 @@ #include "hack.h" #include "bitmaps.h" #include "bmp.h" +#include "paint.h" /** * Sets the frame buffer to the given 16-Bit (5/6/5) RGB color. @@ -82,6 +83,7 @@ case CMD_BITMAP: bitmap(data); break; case CMD_BMP: bmp(data); break; case CMD_DEMO: demo(); break; + case CMD_PAINT: initPaint(); break; default: break; } } diff --git a/cmd.h b/cmd.h index eedf84b..5792f1c 100644 --- a/cmd.h +++ b/cmd.h @@ -23,6 +23,9 @@ /** Display Hack demo: 'd'. */ #define CMD_DEMO 'd' +/** Paint toy: 'a'. */ +#define CMD_PAINT 'a' + /** * Handles the given command. * @param data diff --git a/display.c b/display.c index d1d1218..1e9ac51 100644 --- a/display.c +++ b/display.c @@ -1,5 +1,5 @@ /* - * File: display.h + * File: display.c * Author: torsten.roemer@luniks.net * * Created on 18. April 2023, 21:56 @@ -23,12 +23,15 @@ fillArea(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, color); } -void writeError(char *lines[], uint8_t length) { - setFrame(0xffff); - const __flash Font *hack = &hackFont; - for (uint8_t i = 0; i < length; i++) { - writeString(i * hack->height, 0, hack, lines[i]); - } +void drawRectangle(row_t row, col_t col, width_t width, height_t height, + uint8_t thickness, uint16_t color) { + width -= thickness; + height -= thickness; + + fillArea(row, col, width, thickness, color); + fillArea(row, col + width, thickness, height, color); + fillArea(row + height, col, width + thickness, thickness, color); + fillArea(row, col, thickness, height, color); } width_t writeBitmap(row_t row, col_t col, uint16_t index) { @@ -73,6 +76,14 @@ } } +void writeError(char *lines[], uint8_t length) { + setFrame(0xffff); + const __flash Font *hack = &hackFont; + for (uint8_t i = 0; i < length; i++) { + writeString(i * hack->height, 0, hack, lines[i]); + } +} + void hackDemo(void) { const __flash Font *hack = &hackFont; diff --git a/display.h b/display.h index 9a396b9..9bcf80c 100644 --- a/display.h +++ b/display.h @@ -20,12 +20,18 @@ void setFrame(uint16_t color); /** - * Writes the given lines of text to the top left corner of the display. + * Draws a rectangle with the given origin and dimensions, line thickness + * and color. * - * @param lines text - * @param length number of lines + * @param row + * @param col + * @param width + * @param height + * @param thickness + * @param color */ -void writeError(char *lines[], uint8_t length); +void drawRectangle(row_t row, col_t col, width_t width, height_t height, + uint8_t thickness, uint16_t color); /** * Writes the bitmap with the given index to the given row and column @@ -42,8 +48,8 @@ * Writes the glyph with the given pseudo UTF-8 code point with the given * font to the given row and column and returns the width of the glyph. * - * @param row (8 pixels) - * @param col (1 pixel) + * @param row + * @param col * @param font * @param code * @return glyph width @@ -53,14 +59,22 @@ /** * Writes the given string with the given font to the given row and column. * - * @param row (8 pixels) - * @param col (1 pixel) + * @param row + * @param col * @param font * @param string */ void writeString(row_t row, col_t col, const __flash Font *font, const char *string); /** + * Writes the given lines of text to the top left corner of the display. + * + * @param lines text + * @param length number of lines + */ +void writeError(char *lines[], uint8_t length); + +/** * Displays a demo for the nice Hack font. */ void hackDemo(void); diff --git a/i2c.c b/i2c.c new file mode 100644 index 0000000..f6d52c1 --- /dev/null +++ b/i2c.c @@ -0,0 +1,37 @@ +/* + * File: i2c.c + * Author: torsten.roemer@luniks.net + * + * Created on 15. Dezember 2023, 19:01 + */ + +#include "i2c.h" + +void i2cStart(void) { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTA); + loop_until_bit_is_set(TWCR, TWINT); +} + +void i2cStop(void) { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); +} + +void i2cSend(uint8_t data) { + TWDR = data; + TWCR = (1 << TWINT) | (1 << TWEN); + loop_until_bit_is_set(TWCR, TWINT); +} + +uint8_t i2cReadAck(void) { + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA); + loop_until_bit_is_set(TWCR, TWINT); + + return TWDR; +} + +uint8_t i2cReadNack(void) { + TWCR = (1 << TWINT) | (1 << TWEN); + loop_until_bit_is_set(TWCR, TWINT); + + return TWDR; +} \ No newline at end of file diff --git a/i2c.h b/i2c.h new file mode 100644 index 0000000..53649d7 --- /dev/null +++ b/i2c.h @@ -0,0 +1,47 @@ +/* + * File: i2c.h + * Author: torsten.roemer@luniks.net + * + * Created on 15. Dezember 2023, 19:01 + */ + +#ifndef I2C_H +#define I2C_H + +#include +#include // TODO check status register +#include "pins.h" + +/** + * Begins a message. + */ +void i2cStart(void); + +/** + * Ends a message. + */ +void i2cStop(void); + +/** + * Transmits the given byte of data. + * + * @param data + */ +void i2cSend(uint8_t data); + +/** + * Reads one byte with ack. + * + * @return data + */ +uint8_t i2cReadAck(void); + +/** + * Reads one byte without ack. + * + * @return + */ +uint8_t i2cReadNack(void); + +#endif /* I2C_H */ + diff --git a/nbproject/Makefile-Custom.mk b/nbproject/Makefile-Custom.mk index 37dc026..b615b61 100644 --- a/nbproject/Makefile-Custom.mk +++ b/nbproject/Makefile-Custom.mk @@ -41,8 +41,11 @@ ${OBJECTDIR}/_ext/48b9b4a1/emojis.o \ ${OBJECTDIR}/_ext/48b9b4a1/font.o \ ${OBJECTDIR}/_ext/48b9b4a1/hack.o \ + ${OBJECTDIR}/_ext/48b9b4a1/i2c.o \ ${OBJECTDIR}/_ext/48b9b4a1/spi.o \ - ${OBJECTDIR}/_ext/48b9b4a1/tft.o + ${OBJECTDIR}/_ext/48b9b4a1/tft.o \ + ${OBJECTDIR}/_ext/48b9b4a1/touch.o \ + ${OBJECTDIR}/paint.o # C Compiler Flags @@ -93,6 +96,10 @@ ${MKDIR} -p ${OBJECTDIR}/_ext/48b9b4a1 $(COMPILE.c) -g -DBAUD=9600 -DF_CPU=8000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -std=c99 -o ${OBJECTDIR}/_ext/48b9b4a1/hack.o /home/dode/dev/avrtft/hack.c +${OBJECTDIR}/_ext/48b9b4a1/i2c.o: /home/dode/dev/avrtft/i2c.c + ${MKDIR} -p ${OBJECTDIR}/_ext/48b9b4a1 + $(COMPILE.c) -g -DBAUD=9600 -DF_CPU=8000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9b4a1/i2c.o /home/dode/dev/avrtft/i2c.c + ${OBJECTDIR}/_ext/48b9b4a1/spi.o: /home/dode/dev/avrtft/spi.c ${MKDIR} -p ${OBJECTDIR}/_ext/48b9b4a1 $(COMPILE.c) -g -DBAUD=9600 -DF_CPU=8000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -std=c99 -o ${OBJECTDIR}/_ext/48b9b4a1/spi.o /home/dode/dev/avrtft/spi.c @@ -101,6 +108,14 @@ ${MKDIR} -p ${OBJECTDIR}/_ext/48b9b4a1 $(COMPILE.c) -g -DBAUD=9600 -DF_CPU=8000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -std=c99 -o ${OBJECTDIR}/_ext/48b9b4a1/tft.o /home/dode/dev/avrtft/tft.c +${OBJECTDIR}/_ext/48b9b4a1/touch.o: /home/dode/dev/avrtft/touch.c + ${MKDIR} -p ${OBJECTDIR}/_ext/48b9b4a1 + $(COMPILE.c) -g -DBAUD=9600 -DF_CPU=8000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/_ext/48b9b4a1/touch.o /home/dode/dev/avrtft/touch.c + +${OBJECTDIR}/paint.o: paint.c + ${MKDIR} -p ${OBJECTDIR} + $(COMPILE.c) -g -DBAUD=9600 -DF_CPU=8000000UL -D__AVR_ATmega328P__ -D__flash=volatile -I. -o ${OBJECTDIR}/paint.o paint.c + # Subprojects .build-subprojects: diff --git a/nbproject/configurations.xml b/nbproject/configurations.xml index 6dd52e9..38f67d6 100644 --- a/nbproject/configurations.xml +++ b/nbproject/configurations.xml @@ -12,8 +12,14 @@ emojis.c font.c hack.c + i2c.c + i2c.h + paint.c + paint.h spi.c tft.c + touch.c + touch.h + + + + + + + + + + + + diff --git a/paint.c b/paint.c new file mode 100644 index 0000000..7d73e8d --- /dev/null +++ b/paint.c @@ -0,0 +1,137 @@ +/* + * File: paint.c + * Author: torsten.roemer@luniks.net + * + * Created on 29. Dezember 2023, 18:01 + */ + +#include "paint.h" +#include "usart.h" + +static uint16_t colors[] = { + 0xf800, 0x07e0, 0x001f, + 0xffe0, 0xf81f, 0x07ff, + 0x0000, 0xe71c, 0xffff}; + +static uint8_t tool = TOOL_FREE; +static Point prev = {0}; +static uint16_t color = 0x0; +static uint8_t thick = 3; // line thickness +static uint8_t thoff = 2; // offset to "center" point relative to thickness + +/** + * Paints the color selection. + */ +static void paintColors(void) { + for (uint8_t i = 0; i < CTRL_COUNT; i++) { + fillArea(CTRL_WIDTH * i, 0, CTRL_WIDTH, CTRL_WIDTH, colors[i]); + } +} + +/** + * Paints the tool selection. + */ +static void paintTools(void) { + fillArea(0, DISPLAY_WIDTH - CTRL_WIDTH, + CTRL_WIDTH, CTRL_WIDTH * TOOL_COUNT, 0xffff); + for (uint8_t i = 0; i < TOOL_COUNT; i++) { + drawRectangle(CTRL_WIDTH * i, DISPLAY_WIDTH - CTRL_WIDTH, + CTRL_WIDTH, CTRL_WIDTH + 1, 1, 0x0); + writeBitmap(CTRL_WIDTH * i + BITMAP_PADDING, + DISPLAY_WIDTH - CTRL_WIDTH + BITMAP_PADDING, i); + } +} + +void initPaint() { + setFrame(0xffff); + + // color selection + paintColors(); + + // tool selection + paintTools(); + + // highlight default tool + drawRectangle(CTRL_WIDTH * tool, DISPLAY_WIDTH - CTRL_WIDTH, + CTRL_WIDTH, CTRL_WIDTH + 1, 2, 0x0); +} + +void paintEvent(uint8_t event, Point *point) { + if (point->x < CTRL_WIDTH + thoff) { + if (event == EVENT_PRESS_DOWN) { + // color selected + uint8_t i = point->y / (CTRL_WIDTH + 1); + // repaint colors, highlight and select color + paintColors(); + drawRectangle(CTRL_WIDTH * i, 0, + CTRL_WIDTH, CTRL_WIDTH, 2, 0x0); + color = colors[i]; + } + } else if (point->x > DISPLAY_WIDTH - CTRL_WIDTH - thoff) { + if (event == EVENT_PRESS_DOWN) { + uint8_t i = point->y / (CTRL_WIDTH + 1); + // tool selected + if (i == TOOL_CLEAR) { + // clear canvas + fillArea(0, CTRL_WIDTH, DISPLAY_WIDTH - 2 * CTRL_WIDTH + 1, + DISPLAY_HEIGHT, 0xffff); + } else if (i == TOOL_THICK) { + // increment line thickness + thick += 3; + if (thick > 12) thick = 3; + thoff = thick / 2 + 1; + } else if (i < TOOL_COUNT) { + // repaint tools, highlight and select tool + paintTools(); + drawRectangle(CTRL_WIDTH * i, DISPLAY_WIDTH - CTRL_WIDTH, + CTRL_WIDTH, CTRL_WIDTH + 1, 2, 0x0); + tool = i; + } + prev = (Point){-1}; + } + } else { + paintPoint(event, point); + } +} + +void paintPoint(uint8_t event, Point *point) { + if (tool == TOOL_ERASER) { + fillArea(point->y - thoff, point->x - thoff, thick, thick, 0xffff); + } else { + fillArea(point->y - thoff, point->x - thoff, thick, thick, color); + } + + if (prev.x != -1) { + // connect previous and current point with a straight line if distance > 1 + if ((tool == TOOL_LINE) || + (tool == TOOL_FREE && event == EVENT_CONTACT)) { + float d = sqrt(pow(point->x - prev.x, 2) + pow(point->y - prev.y, 2)); + if (d > 1) { + float xd = (point->x - prev.x) / d; + float yd = (point->y - prev.y) / d; + + for (int i = 1; i < d; i++) { + col_t xi = prev.x + xd * i; + row_t yi = prev.y + yd * i; + fillArea(yi - thoff, xi - thoff, thick, thick, color); + } + } + } + + // draw a rectangle spanning the previous and current point + if (tool == TOOL_RECT && event == EVENT_PRESS_DOWN) { + row_t x1 = fmin(prev.x, point->x); + row_t y1 = fmin(prev.y, point->y); + col_t x2 = fmax(prev.x, point->x); + col_t y2 = fmax(prev.y, point->y); + + drawRectangle(y1 - thoff, x1 - thoff, + x2 - x1 + thick, y2 - y1 + thick, thick, color); + // unset previous point and leave (for now) + prev = (Point){-1}; + return; + } + } + + prev = *point; +} \ No newline at end of file diff --git a/paint.h b/paint.h new file mode 100644 index 0000000..e0d7bbf --- /dev/null +++ b/paint.h @@ -0,0 +1,53 @@ +/* + * File: paint.h + * Author: torsten.roemer@luniks.net + * + * Created on 29. Dezember 2023, 18:01 + */ + +#ifndef PAINT_H +#define PAINT_H + +#include +#include +#include + +#include "tft.h" +#include "touch.h" +#include "display.h" + +#define CTRL_COUNT 9 +#define TOOL_COUNT 6 +#define BITMAP_PADDING 5 +#define CTRL_WIDTH DISPLAY_HEIGHT / CTRL_COUNT + +#define TOOL_FREE 0 +#define TOOL_LINE 1 +#define TOOL_RECT 2 +#define TOOL_ERASER 3 +#define TOOL_THICK 4 +#define TOOL_CLEAR 5 + +/** + * Initializes and displays the paint application. + */ +void initPaint(void); + +/** + * Handles the given touch event and point. + * + * @param event + * @param point + */ +void paintEvent(uint8_t event, Point *point); + +/** + * Paints the given point, connecting points with a distance > 1 with + * a straight line during "contact" touch event or draws a rectangle. + * + * @param event + * @param point + */ +void paintPoint(uint8_t event, Point *point); + +#endif /* PAINT_H */ diff --git a/pins.h b/pins.h index ae5a832..2b47dda 100644 --- a/pins.h +++ b/pins.h @@ -18,6 +18,13 @@ #define PIN_MISO PB4 #define PIN_SCK PB5 +/* I2C/Touch */ +#define DDR_I2C DDRC +#define PORT_I2C PORTC +#define PIN_SCL PC5 +#define PIN_SDA PC4 +#define PIN_TINT PD2 // touch controller interrupt + /* Display SPI */ #define DDR_DSPI DDRB #define PORT_DSPI PORTB diff --git a/tft.c b/tft.c index f39291c..bb3fa4b 100644 --- a/tft.c +++ b/tft.c @@ -17,6 +17,19 @@ #include "bitmaps.h" +/** + * Converts the given 8 pixel in 1-Bit monochrome to 16-Bit RGB (5/6/5) color + * stored in the given array of 16 bytes. + * + * @param grey 8 pixel in 1-Bit monochrome + * @param rgb 8 pixel in 16-Bit RGB (5/6/5) color + */ +static void mono1ToRGB16(uint8_t mono, uint8_t *rgb) { + for (uint8_t i = 0; i < 16; i++) { + rgb[i] = (mono & (1 << ((15 - i) >> 1))) ? 0x0 : 0xff; + } +} + /* * Converts the given two pixel in 4-Bit greyscale to 16-Bit RGB (5/6/5) color * stored in the given array of four bytes. @@ -28,24 +41,20 @@ uint8_t grey4 = ((grey >> 4) & 1); uint8_t grey0 = ((grey >> 0) & 1); - rgb[0] = grey; - rgb[0] &= ~0b00001111; + rgb[0] = (grey & 0xf0); rgb[0] |= grey4 << 3; rgb[0] |= (grey >> 5); - rgb[1] = (grey << 3); - rgb[1] &= ~0b01111111; - rgb[1] |= (grey4 << 6) | (grey4 << 5); - rgb[1] |= (grey >> 3); - rgb[1] &= ~0b00000001; - rgb[1] |= (grey4 << 0); + rgb[1] = ((grey & 0xf0) << 3); + rgb[1] |= ((grey & 0xf0) >> 3); + rgb[1] |= (grey4 << 6) | (grey4 << 5) | (grey4 << 0); rgb[2] = (grey << 4); - rgb[2] |= (grey >> 1); rgb[2] |= (grey0 << 3); + rgb[2] |= ((grey & 0x0f) >> 1); rgb[3] = (grey << 7); - rgb[3] |= (grey << 1); + rgb[3] |= ((grey & 0x0f) << 1); rgb[3] |= (grey0 << 6) | (grey0 << 5) | (grey0 << 0); } @@ -58,24 +67,100 @@ PORT_DISP |= (1 << PIN_RST); } -void displaySetCmd(void) { +/** + * Sets display to send a command. + */ +static void displaySetCmd(void) { PORT_DSPI &= ~(1 << PIN_DC); } -void displaySetData(void) { +/** + * Sets display to send data. + */ +static void displaySetData(void) { PORT_DSPI |= (1 << PIN_DC); } -void displayCmd(uint8_t cmd) { +/** + * Sends the given command to the display. + * + * @param cmd + */ +static void displayCmd(uint8_t cmd) { displaySetCmd(); transmit(cmd); } -void displayData(uint8_t data) { +/** + * Sends the given data to the display. + * + * @param data + */ +static void displayData(uint8_t data) { displaySetData(); transmit(data); } +/** + * Sets horizontal and/or vertical flip. + * + * @param hflip + * @param vflip + */ +static void madctl(bool hflip, bool vflip) { + // Memory data access control + uint8_t madctl = 0b00110110; + madctl |= (VFLIP << 7); + madctl |= (HFLIP << 6); + madctl |= (BGR << 3); + + if (vflip) { + // Row Address Order (MY) + madctl ^= (1 << 7); + } + if (hflip) { + // Column Address Order (MX) + madctl ^= (1 << 6); + } + + displaySel(); + displayCmd(MADCTL); + displayData(madctl); + displayDes(); +} + +/** + * Sets the given column start and end address. + * + * @param xs start address + * @param xe end address + */ +static void caset(uint16_t xs, uint16_t xe) { + displaySel(); + displayCmd(CASET); + displayData(xs >> 8); + displayData(xs); + displayData(xe >> 8); + displayData(xe); + displayDes(); +} + +/** + * Sets the given row start and end address. + * + * @param ys start address + * @param ye end address + */ +static void raset(uint16_t ys, uint16_t ye) { + displaySel(); + displayCmd(RASET); + displayData(ys >> 8); + displayData(ys); + displayData(ye >> 8); + displayData(ye); + displayDes(); +} + void initDisplay(void) { // Hardware reset hwReset(); @@ -125,129 +210,6 @@ printString("done initializing display\r\n"); } -void fillArea(row_t row, col_t col, - width_t width, height_t height, - uint16_t color) { - - // X address start/end - uint16_t xs = col; - uint16_t xe = col + width - 1; - displaySel(); - displayCmd(CASET); - displayData(xs >> 8); - displayData(xs); - displayData(xe >> 8); - displayData(xe); - displayDes(); - - // Y address start/end - uint16_t ys = row; - uint16_t ye = row + height - 1; - displaySel(); - displayCmd(RASET); - displayData(ys >> 8); - displayData(ys); - displayData(ye >> 8); - displayData(ye); - displayDes(); - - // Memory write - displaySel(); - displayCmd(RAMWR); - displaySetData(); - - bytes_t pixels = (bytes_t)width * (bytes_t)height; - for (bytes_t i = 0; i < pixels; i++) { - transmit(color >> 8); - transmit(color); - } - - displayDes(); -} - -void setArea(row_t row, col_t col, - width_t width, height_t height, - bool hflip, bool vflip) { - - // Memory data access control - uint8_t madctl = 0b11110110; - madctl &= ~(VFLIP << 7); - madctl &= ~(HFLIP << 6); - madctl |= (BGR << 3); - - if (vflip) { - // Row Address Order (MY) - madctl ^= (1 << 7); - } - if (hflip) { - // Column Address Order (MX) - madctl ^= (1 << 6); - } - - displaySel(); - displayCmd(MADCTL); - displayData(madctl); - displayDes(); - - // 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); - displayData(xs); - displayData(xe >> 8); - displayData(xe); - displayDes(); - - // Y address start/end - uint16_t ys = row; - uint16_t ye = row + height - 1; - if (hflip) { - ys = DISPLAY_HEIGHT - row - height; - ye = DISPLAY_HEIGHT - row - 1; - } - displaySel(); - displayCmd(RASET); - displayData(ys >> 8); - displayData(ys); - displayData(ye >> 8); - displayData(ye); - displayDes(); -} - -void writeData(const __flash uint8_t *bitmap, - width_t width, height_t height, - space_t space) { - // Memory write - displaySel(); - displayCmd(RAMWR); - displaySetData(); - - if (space == SPACE_GREY4) { - 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++) { - transmit(rgb[j]); - } - } - } else { - // SPACE_RGB16 - bytes_t bytes = (bytes_t)width * (bytes_t)height * 2; - for (bytes_t i = 0; i < bytes; i++) { - transmit(bitmap[i]); - } - } - - displayDes(); -} - void writeStart(void) { // Memory write displaySel(); @@ -264,3 +226,93 @@ // Memory write displayDes(); } + +void fillArea(row_t row, col_t col, + width_t width, height_t height, + uint16_t color) { + + madctl(false, false); + + // X address start/end + uint16_t xs = col; + uint16_t xe = col + width - 1; + caset(xs, xe); + + // Y address start/end + uint16_t ys = row; + uint16_t ye = row + height - 1; + raset(ys, ye); + + writeStart(); + + bytes_t pixels = (bytes_t)width * (bytes_t)height; + for (bytes_t i = 0; i < pixels; i++) { + transmit(color >> 8); + transmit(color); + } + + writeEnd(); +} + +void setArea(row_t row, col_t col, + width_t width, height_t height, + bool hflip, bool vflip) { + + madctl(hflip, vflip); + + // 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; + } + caset(xs, xe); + + // Y address start/end + uint16_t ys = row; + uint16_t ye = row + height - 1; + if (hflip) { + ys = DISPLAY_HEIGHT - row - height; + ye = DISPLAY_HEIGHT - row - 1; + } + raset(ys, ye); +} + +void writeData(const __flash uint8_t *bitmap, + width_t width, height_t height, + space_t space) { + writeStart(); + + switch (space) { + case SPACE_MONO1: { + bytes_t bytes = width * height / 8; + for (uint16_t i = 0; i < bytes; i++) { + uint8_t rgb[16]; + mono1ToRGB16(bitmap[i], rgb); + for (uint8_t j = 0; j < 16; j++) { + transmit(rgb[j]); + } + } + }; break; + case SPACE_GREY4: { + bytes_t bytes = width * height / 2; + for (uint16_t i = 0; i < bytes; i++) { + uint8_t rgb[4]; + grey4ToRGB16(bitmap[i], rgb); + for (uint8_t j = 0; j < 4; j++) { + transmit(rgb[j]); + } + } + }; break; + default: { + // SPACE_RGB16 + bytes_t bytes = width * height * 2; + for (uint16_t i = 0; i < bytes; i++) { + transmit(bitmap[i]); + } + } + } + + writeEnd(); +} diff --git a/tft.h b/tft.h index ddfbca8..7f359c4 100644 --- a/tft.h +++ b/tft.h @@ -49,37 +49,33 @@ #endif // TODO use enum? typedef? +#define SPACE_MONO1 1 #define SPACE_GREY4 4 #define SPACE_RGB16 16 /** - * Sets display to send a command. - */ -void displaySetCmd(void); - -/** - * Sets display to send data. - */ -void displaySetData(void); - -/** - * Sends the given command to the display. - * @param cmd - */ -void displayCmd(uint8_t cmd); - -/** - * Sends the given data to the display. - * @param data - */ -void displayData(uint8_t data); - -/** * Initializes the display. */ void initDisplay(void); /** + * Sets to write data to display RAM. + */ +void writeStart(void); + +/** + * Writes the given byte to display RAM. + * + * @param byte + */ +void writeByte(uint8_t byte); + +/** + * Completes writing data to display RAM. + */ +void writeEnd(void); + +/** * Sets the given color in the given area of the display. * * @param row row in pixels, origin top left @@ -118,21 +114,4 @@ width_t width, height_t height, space_t space); -/** - * Sets to write data to display RAM. - */ -void writeStart(void); - -/** - * Writes the given byte to display RAM. - * - * @param byte - */ -void writeByte(uint8_t byte); - -/** - * Completes writing data to display RAM. - */ -void writeEnd(void); - #endif /* TFT_H */ diff --git a/touch.c b/touch.c new file mode 100644 index 0000000..7c5817e --- /dev/null +++ b/touch.c @@ -0,0 +1,52 @@ +/* + * File: touch.c + * Author: torsten.roemer@luniks.net + * + * Created on 12. Dezember 2023, 23:44 + */ + +#include +#include "touch.h" +#include "i2c.h" +#include "tft.h" +#include "usart.h" + +uint8_t readTouch(Point *point) { + i2cStart(); + i2cSend(FT62XX_WRITE); + // start reading at P1_XH + i2cSend(0x03); + + i2cStart(); + i2cSend(FT62XX_READ); + + // TD_STATUS + // uint8_t tdStatus = i2cReadAck(); + // tdStatus = (tdStatus & 0x0f); + + // P1_X + uint8_t xh = i2cReadAck(); + uint8_t xl = i2cReadAck(); + uint8_t eventFlag = (xh & 0xc0) >> 6; + // swapping x and y according to display's row/column exchange default + point->y = (xh & 0x0f) << 8; + point->y |= xl; + + // P1_Y + uint8_t yh = i2cReadAck(); + uint8_t yl = i2cReadNack(); + // swapping x and y according to display's row/column exchange default + point->x = (yh & 0x0f) << 8; + point->x |= yl; + + i2cStop(); + + if (!VFLIP) { + point->x = DISPLAY_WIDTH - point->x; + } + if (HFLIP) { + point->y = DISPLAY_HEIGHT - point->y; + } + + return eventFlag; +} diff --git a/touch.h b/touch.h new file mode 100644 index 0000000..7a8d470 --- /dev/null +++ b/touch.h @@ -0,0 +1,33 @@ +/* + * File: touch.h + * Author: torsten.roemer@luniks.net + * + * Created on 12. Dezember 2023, 23:44 + */ + +#include "types.h" + +#ifndef TOUCH_H +#define TOUCH_H + +#define FT62XX_WRITE (0x38 << 1) & 0xfe +#define FT62XX_READ (0x38 << 1) | 0x01 + +#define EVENT_PRESS_DOWN 0 +#define EVENT_LIFT_UP 1 +#define EVENT_CONTACT 2 +#define EVENT_NO_EVENT 3 + +/** + * Reads the current touch position into the given point and returns + * the touch event. + * + * It seems more data than that (besides the touch count) is not available; + * i.e. the gesture always reads 0x00 and the weight 0x10. + * + * @param point touch position + * @return touch event + */ +uint8_t readTouch(Point *point); + +#endif /* TOUCH_H */ diff --git a/types.h b/types.h index bc3b920..99dfa2d 100644 --- a/types.h +++ b/types.h @@ -26,5 +26,13 @@ /* Number of glyphs of a font */ typedef uint8_t length_t; +/** + * A point with its x and y coordinates. + */ +typedef struct { + int16_t x; + int16_t y; +} Point; + #endif /* TYPES_H */ diff --git a/usart.c b/usart.c index 958f09d..9ea421c 100644 --- a/usart.c +++ b/usart.c @@ -87,6 +87,12 @@ printString(buf); } +void printHex(uint8_t data) { + char buf[7]; + snprintf(buf, sizeof (buf), "0x%x\r\n", data); + printString(buf); +} + void printByte(uint8_t byte) { char string[] = {'0', 'b', '?', '?', '?', '?', '?', '?', '?', '?', '\r', '\n', '\0'}; for (uint8_t i = 8; i-- > 0; ) { diff --git a/usart.h b/usart.h index 45f5fe9..52ac1c6 100644 --- a/usart.h +++ b/usart.h @@ -61,6 +61,12 @@ void printUint(uint8_t data); /** + * Prints the given unsigned integer in hex notation including CR + LF + * via USART. + */ +void printHex(uint8_t data); + +/** * Prints the given unsigned integer in binary notation including CR + LF * via USART. */