diff --git a/src/lcd/lcd.c b/src/lcd/lcd.c new file mode 100644 index 0000000000000000000000000000000000000000..d5f7ea57d35a4eaf8e37774722b174db097a55a6 --- /dev/null +++ b/src/lcd/lcd.c @@ -0,0 +1,340 @@ +/* Author: Steve Gunn + * Licence: This work is licensed under the Creative Commons Attribution License. + * View this license at http://creativecommons.org/about/licenses/ + * + * + * - Jan 2015 Modified for LaFortuna (Rev A, black edition) [KPZ] + */ + +#include <avr/io.h> +#include <avr/interrupt.h> +#include <util/delay.h> +#include "font.h" +#include "ili934x.h" +#include "lcd.h" + +lcd display; + +void init_lcd() +{ + /* Enable extended memory interface with 10 bit addressing */ + XMCRB = _BV(XMM2) | _BV(XMM1); + XMCRA = _BV(SRE); + DDRC |= _BV(RESET); + DDRB |= _BV(BLC); + _delay_ms(1); + PORTC &= ~_BV(RESET); + _delay_ms(20); + PORTC |= _BV(RESET); + _delay_ms(120); + write_cmd(DISPLAY_OFF); + write_cmd(SLEEP_OUT); + _delay_ms(60); + write_cmd_data(INTERNAL_IC_SETTING, 0x01); + write_cmd(POWER_CONTROL_1); + write_data16(0x2608); + write_cmd_data(POWER_CONTROL_2, 0x10); + write_cmd(VCOM_CONTROL_1); + write_data16(0x353E); + write_cmd_data(VCOM_CONTROL_2, 0xB5); + write_cmd_data(INTERFACE_CONTROL, 0x01); + write_data16(0x0000); + write_cmd_data(PIXEL_FORMAT_SET, 85); /* 16bit/pixel */ + set_orientation(West); + clear_screen(); + display.x = 0; + display.y = 0; + display.background = BLACK; + display.foreground = GREEN; + write_cmd(DISPLAY_ON); + _delay_ms(50); + write_cmd_data(TEARING_EFFECT_LINE_ON, 0x00); + EICRB |= _BV(ISC61); + PORTB |= _BV(BLC); +} + +void lcd_brightness(uint8_t i) +{ + /* Configure Timer 2 Fast PWM Mode 3 */ + TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20); + TCCR2B = _BV(CS20); + OCR2A = i; +} + +void set_orientation(orientation o) +{ + display.orient = o; + write_cmd(MEMORY_ACCESS_CONTROL); + if (o==North) { + display.width = LCDWIDTH; + display.height = LCDHEIGHT; + write_data(0x48); + } + else if (o==West) { + display.width = LCDHEIGHT; + display.height = LCDWIDTH; + write_data(0xE8); + } + else if (o==South) { + display.width = LCDWIDTH; + display.height = LCDHEIGHT; + write_data(0x88); + } + else if (o==East) { + display.width = LCDHEIGHT; + display.height = LCDWIDTH; + write_data(0x28); + } + write_cmd(COLUMN_ADDRESS_SET); + write_data16(0); + write_data16(display.width-1); + write_cmd(PAGE_ADDRESS_SET); + write_data16(0); + write_data16(display.height-1); +} + + + +void set_frame_rate_hz(uint8_t f) +{ + uint8_t diva, rtna, period; + if (f>118) + f = 118; + if (f<8) + f = 8; + if (f>60) { + diva = 0x00; + } else if (f>30) { + diva = 0x01; + } else if (f>15) { + diva = 0x02; + } else { + diva = 0x03; + } + /* !!! FIXME !!! [KPZ-30.01.2015] */ + /* Check whether this works for diva > 0 */ + /* See ILI9341 datasheet, page 155 */ + period = 1920.0/f; + rtna = period >> diva; + write_cmd(FRAME_CONTROL_IN_NORMAL_MODE); + write_data(diva); + write_data(rtna); +} + +void fill_rectangle(rectangle r, uint16_t col) +{ + setupDraw(r); +/* uint16_t x, y; + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++) + write_data16(col); +*/ + uint16_t wpixels = r.right - r.left + 1; + uint16_t hpixels = r.bottom - r.top + 1; + uint8_t mod8, div8; + uint16_t odm8, odd8; + if (hpixels > wpixels) { + mod8 = hpixels & 0x07; + div8 = hpixels >> 3; + odm8 = wpixels*mod8; + odd8 = wpixels*div8; + } else { + mod8 = wpixels & 0x07; + div8 = wpixels >> 3; + odm8 = hpixels*mod8; + odd8 = hpixels*div8; + } + uint8_t pix1 = odm8 & 0x07; + while(pix1--) + write_data16(col); + + uint16_t pix8 = odd8 + (odm8 >> 3); + while(pix8--) { + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + write_data16(col); + } +} + +void fill_rectangle_indexed(rectangle r, uint16_t* col) +{ + uint16_t x, y; + setupDraw(r); + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++) + write_data16(*col++); +} + +void fill_rectangle_indexed_MEM(rectangle r, PGM_P imgdata) +{ + uint16_t x, y; + rectangleInRegion(&r); + setupDraw(r); + uint16_t pixVal; + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++){ + pixVal = pgm_read_word(imgdata); + imgdata+=2; + write_data16(pixVal); + } +} + +void compositeTest(rectangle r, uint16_t* copyReg){ + uint16_t x, y; + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_READ); + uint16_t* ptr = copyReg;read_data(); + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++){ + unsigned char p0 = read_data(); + unsigned char p1 = read_data(); + unsigned char p2 = read_data(); + unsigned char r = p0 >> 2; + unsigned char g = p1 >> 2; + unsigned char b = p2 >> 2; + *ptr = (((uint16_t)b)>>1) + (((uint16_t)g) << 5) + ((((uint16_t)r)>>1) << 11); + ptr+=2; + } + + write_cmd(MEMORY_WRITE); + ptr = copyReg; + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++){ + write_data16(*ptr); + ptr+=2; + } +} + +void screenDump(rectangle r){ + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_READ); + uint16_t x, y; + read_data(); //Throw away a byte + for(x=r.left; x<=r.right; x++) + for(y=r.top; y<=r.bottom; y++){ + unsigned char r = read_data() >> 2; + unsigned char g = read_data() >> 2; + unsigned char b = read_data() >> 2; + uint16_t value = (((uint16_t)b)>>1) + (((uint16_t)g) << 5) + ((((uint16_t)r)>>1) << 11); + } +} + +void clear_screen() +{ + display.x = 0; + display.y = 0; + rectangle r = {0, display.width-1, 0, display.height-1}; + fill_rectangle(r, display.background); +} + +void display_char(char c) +{ + if (c == '\n') { + display.x = 0; + display.y += 16; + } + if (display.y > 200) { + display.y = 0; + rectangle r; + r.left = 0; + r.right = 319; + r.top = 0; + r.bottom = 239; + fill_rectangle(r, 0); + } + + uint16_t x, y; + PGM_P fdata; + uint8_t bits, mask; + uint16_t sc=display.x, ec=display.x + 4, sp=display.y, ep=display.y + 7; + + if (c < 32 || c > 126) return; + fdata = (c - ' ')*5 + font5x7; + write_cmd(PAGE_ADDRESS_SET); + write_data16(sp); + write_data16(ep); + for(x=sc; x<=ec; x++) { + write_cmd(COLUMN_ADDRESS_SET); + write_data16(x); + write_data16(x); + write_cmd(MEMORY_WRITE); + bits = pgm_read_byte(fdata++); + for(y=sp, mask=0x01; y<=ep; y++, mask<<=1) + write_data16((bits & mask) ? display.foreground : display.background); + } + write_cmd(COLUMN_ADDRESS_SET); + write_data16(x); + write_data16(x); + write_cmd(MEMORY_WRITE); + for(y=sp; y<=ep; y++) + write_data16(display.background); + + display.x += 6; + if (display.x >= display.width) { display.x=0; display.y+=8; } +} + +void display_string(char *str) +{ + uint8_t i; + for(i=0; str[i]; i++) + display_char(str[i]); +} + +void display_string_xy(char *str, uint16_t x, uint16_t y) +{ + uint8_t i; + display.x = x; + display.y = y; + for(i=0; str[i]; i++) + display_char(str[i]); +} + +void rectangleInRegion(rectangle* r){ //LETS FIX STUFFFF!! + if(r->top > r->bottom) + r->top = r->bottom; + if(r->top > 32000) + r->top = 0; + if(r->bottom > 32000) + r->bottom = 0; + if(r->top >= display.height) + r->top = display.height-1; + if(r->bottom >= display.height) + r->bottom = display.height-1; + + if(r->left > r->right) + r->left = r->right; + if(r->left > 32000) + r->left = 0; + if(r->right > 32000) + r->right = 0; + if(r->left >= display.width) + r->left = display.width-1; + if(r->right >= display.width) + r->right = display.width-1; +} + +void setupDraw(rectangle r){ + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(r.top); + write_data16(r.bottom); + write_cmd(MEMORY_WRITE); +} +