/* * Copyright 2017 Oleg Borodin * */ #include #include #include #include #include #include #include #include #include #define MADCTL_MY 0x80 #define MADCTL_MX 0x40 #define MADCTL_MV 0x20 #define MADCTL_ML 0x10 #define MADCTL_RGB 0x00 #define MADCTL_BGR 0x08 #define MADCTL_MH 0x04 #define LCD_DELTA_X 1 #define LCD_DELTA_Y 0 void lcd_write_command(uint8_t c) { REG_SETDOWN_BIT(PORTB, PIN_A0); REG_SETDOWN_BIT(PORTB, PIN_SS); spi_write_byte(c); REG_SETUP_BIT(PORTB, PIN_A0); } void lcd_write_byte(uint8_t c) { REG_SETUP_BIT(PORTB, PIN_A0); REG_SETDOWN_BIT(PORTB, PIN_SS); spi_write_byte(c); REG_SETUP_BIT(PORTB, PIN_A0); } void lcd_write_word(uint16_t w) { REG_SETUP_BIT(PORTB, PIN_A0); REG_SETDOWN_BIT(PORTB, PIN_SS); spi_write_word(w); REG_SETUP_BIT(PORTB, PIN_A0); } void lcd_write_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) { lcd_addr_window(x, y, (x + w), (y + h)); REG_SETUP_BIT(PORTB, PIN_A0); REG_SETDOWN_BIT(PORTB, PIN_SS); spi_write_word_array(color, (w + 1) * (h + 1)); REG_SETUP_BIT(PORTB, PIN_A0); } void lcd_reset(void) { REG_SETUP_BIT(PORTB, PIN_RESET); _delay_ms(100); REG_SETDOWN_BIT(PORTB, PIN_RESET); _delay_ms(100); REG_SETUP_BIT(PORTB, PIN_RESET); _delay_ms(100); } void lcd_init(void) { REG_SETUP_BIT(PORTB, PIN_RESET); /* 1: Software reset, 0 args, w/delay */ lcd_write_command(ST7735_SWRESET); /* 150 ms delay */ _delay_ms(150); /* 2: Out of sleep mode, 0 args, w/delay */ lcd_write_command(ST7735_SLPOUT); /* 500 ms delay */ _delay_ms(500); /* 3: Frame rate ctrl - normal mode, 3 args: */ lcd_write_command(ST7735_FRMCTR1); /* Rate = fosc/(1x2+40) * (LINE+2C+2D) */ lcd_write_byte(0x01); lcd_write_byte(0x2C); lcd_write_byte(0x2D); /* 4: Frame rate control - idle mode, 3 args: */ lcd_write_command(ST7735_FRMCTR2); /* Rate = fosc/(1x2+40) * (LINE+2C+2D) */ lcd_write_byte(0x01); lcd_write_byte(0x2C); lcd_write_byte(0x2D); /* 5: Frame rate ctrl - partial mode, 6 args: */ lcd_write_command(ST7735_FRMCTR3); /* Dot inversion mode */ lcd_write_byte(0x01); lcd_write_byte(0x2C); lcd_write_byte(0x2D); /* Line inversion mode */ lcd_write_byte(0x01); lcd_write_byte(0x2C); lcd_write_byte(0x2D); /* 6: Display inversion ctrl, 1 arg, no delay: */ lcd_write_command(ST7735_INVCTR); /* No inversion */ lcd_write_byte(0x07); /* 7: Power control, 3 args, no delay: */ lcd_write_command(ST7735_PWCTR1); lcd_write_byte(0xA2); /* -4.6V */ lcd_write_byte(0x02); /* AUTO mode */ lcd_write_byte(0x84); /* 8: Power control, 1 arg, no delay: */ lcd_write_command(ST7735_PWCTR2); /* VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */ lcd_write_byte(0xC5); /* 9: Power control, 2 args, no delay: */ lcd_write_command(ST7735_PWCTR3); /* Opamp current small */ lcd_write_byte(0x0A); /* Boost frequency */ lcd_write_byte(0x00); /* 10: Power control, 2 args, no delay: */ lcd_write_command(ST7735_PWCTR4); /* BCLK/2, Opamp current small & Medium low */ lcd_write_byte(0x8A); lcd_write_byte(0x2A); /* 11: Power control, 2 args, no delay: */ lcd_write_command(ST7735_PWCTR5); lcd_write_byte(0x8A); lcd_write_byte(0xEE); /* 12: Power control, 1 arg, no delay: */ lcd_write_command(ST7735_VMCTR1); lcd_write_byte(0x0E); /* 13: Don't invert display, no args, no delay */ lcd_write_command(ST7735_INVOFF); /* 14: Memory access control (directions), 1 arg: */ lcd_write_command(ST7735_MADCTL); /* row addr/col addr, bottom to top refresh, RGB order */ lcd_write_byte(0xC0); /* 15: Set color mode, 1 arg + delay: */ lcd_write_command(ST7735_COLMOD); /* 16-bit color 5-6-5 color format */ lcd_write_byte(0x05); /* 10 ms delay */ _delay_ms(10); /* 1: Column addr set, 4 args, no delay */ lcd_write_command(ST7735_CASET); /* XSTART = 0 */ lcd_write_byte(0x00); lcd_write_byte(0x00); /* XEND = 127 */ lcd_write_byte(0x00); lcd_write_byte(ST7735_TFTWIDTH /* 0x7F */); /* 2: Row addr set, 4 args, no delay: */ lcd_write_command(ST7735_RASET); /* XSTART = 0 */ lcd_write_byte(0x00); lcd_write_byte(0x00); /* XEND = 127 */ lcd_write_byte(0x00); lcd_write_byte(ST7735_TFTHEIGHT /* 0x7F */); /* 1: Magical unicorn dust, 16 args, no delay: */ lcd_write_command(ST7735_GMCTRP1); lcd_write_byte(0x02); lcd_write_byte(0x1c); lcd_write_byte(0x07); lcd_write_byte(0x12); lcd_write_byte(0x37); lcd_write_byte(0x32); lcd_write_byte(0x29); lcd_write_byte(0x2d); lcd_write_byte(0x29); lcd_write_byte(0x25); lcd_write_byte(0x2B); lcd_write_byte(0x39); lcd_write_byte(0x00); lcd_write_byte(0x01); lcd_write_byte(0x03); lcd_write_byte(0x10); /* 2: Sparkles and rainbows, 16 args, no delay: */ lcd_write_command(ST7735_GMCTRN1); lcd_write_byte(0x03); lcd_write_byte(0x1d); lcd_write_byte(0x07); lcd_write_byte(0x06); lcd_write_byte(0x2E); lcd_write_byte(0x2C); lcd_write_byte(0x29); lcd_write_byte(0x2D); lcd_write_byte(0x2E); lcd_write_byte(0x2E); lcd_write_byte(0x37); lcd_write_byte(0x3F); lcd_write_byte(0x00); lcd_write_byte(0x00); lcd_write_byte(0x02); lcd_write_byte(0x10); /* 3: Normal display on, no args, w/delay */ lcd_write_command(ST7735_NORON); _delay_ms(10); /* 4: Main screen turn on, no args w/delay */ lcd_write_command(ST7735_DISPON); _delay_ms(100); } void lcd_addr_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { lcd_write_command(ST7735_CASET); lcd_write_word(x0 + LCD_DELTA_X); lcd_write_word(x1 + LCD_DELTA_X); lcd_write_command(ST7735_RASET); lcd_write_word(y0 + LCD_DELTA_Y); lcd_write_word(y1 + LCD_DELTA_Y); lcd_write_command(ST7735_RAMWR); } void lcd_draw_pixel(uint8_t x, uint8_t y, uint16_t color) { //if (x > lcd_screen.height || y > lcd_screen.width) // return; lcd_addr_window(x, y, x, y); lcd_write_word(color); } #define swap(a, b) { int16_t t = a; a = b; b = t; } void lcd_draw_line(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) { int16_t steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swap(x0, y0); swap(x1, y1); } if (x0 > x1) { swap(x0, x1); swap(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; } while (x0 <= x1) { if (steep) { lcd_draw_pixel(y0, x0, color); } else { lcd_draw_pixel(x0, y0, color); } err -= dy; if (err < 0) { y0 += ystep; err += dx; } x0++; } } void lcd_draw_vline(int16_t x, int16_t y, int16_t l, uint16_t color) { lcd_write_rect(x, y, (l - 1), 0, color); } void lcd_draw_hline(int16_t x, int16_t y, int16_t l, uint16_t color) { lcd_write_rect(x, y, 0, (l - 1), color); } void lcd_draw_rest(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h, uint16_t color) { lcd_draw_hline(x1, y1, w, color); lcd_draw_vline(x1, y1, h, color); lcd_draw_hline((x1 + h) - 0, y1, w, color); lcd_draw_vline(x1, (y1 + w) - 0, h, color); } uint16_t lcd_rgb2color(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } void lcd_orient0(void) { lcd_write_command(ST7735_MADCTL); lcd_write_byte(MADCTL_RGB); } void lcd_draw_char(uint16_t xbase, uint16_t ybase, font_t *font, uint8_t c) { if (c < font->start || c > (font->start + font->length)) c = ' '; c = c - font->start; #if 0 //ybase += font->width; //xbase += font->height; for (uint8_t h = 0; h < font->height; h++) { for (uint8_t w = 0; w < font->width; w++) { if (pgm_read_byte(&(font->bitmap[(c) * font->height + h])) & (1 << w)) lcd_draw_pixel((xbase - h), (ybase - w), 0xffff); else lcd_draw_pixel((xbase - h), (ybase - w), 0x0000); } } #else lcd_addr_window(xbase, ybase, xbase + font->height - 1, ybase + font->width - 1); for (uint8_t w = font->width; w > 0; w--) { for (uint8_t h = font->height; h > 0; h--) { if (pgm_read_byte(&(font->bitmap[(c) * font->height + (h - 1)])) & (1 << (w - 1))) lcd_write_word(0xffff); else lcd_write_word(0x0000); } } #endif } void lcd_clear(void) { _delay_ms(100); lcd_write_rect(0, 0, ST7735_TFTWIDTH, ST7735_TFTHEIGHT, 0x0000); _delay_ms(100); }