#include "UTFT.h"
#include <util/delay.h>
#include <stdlib.h>
static void myseek(FILE*f,int dist) {
if (f->flags&__SSTR) { // mine! Do fast access
f->len+=(int)dist;
}//else fseek(f,dist,SEEK_CUR);
}
static word mygetw(FILE*f) {
word w;
if (f->flags&__SSTR) { // mine! Do fast access
word*p=(word*)f->len;
if (f->flags&__SPGM) w=pgm_read_word(p);
else w=*p;
++p;
f->len=(int)p;
}else{ // not mine! Use function pointer
w=fgetc(f)&0xFF;
w|=fgetc(f)<<8;
}
return w;
}
/********************
* Basic LCD access *
********************/
void UTFT::LCD_Writ_Bus(word w) {
#if DISP_TRANSFER==8
PORTD=w>>8;
pulse_low(P_WR,B_WR);
PORTD=w;
pulse_low(P_WR,B_WR);
#elif DISP_TRANSFER==16
PORTD=w>>8;
PORTC=PORTC&0xFC|(byte)w>>6&3;
PORTB=(byte)w&0x3F;
pulse_low(P_WR,B_WR);
#else
# error "unimplemented display transfer mode"
#endif
}
void UTFT::_set_direction_registers() {
#ifdef P_RST // has RESET connection?
PORTC|=B_RS|B_WR|B_CS|B_RST;
DDRC|=B_RS|B_WR|B_CS|B_RST;
#else
PORTC|=B_RS|B_WR|B_CS;
DDRC|=B_RS|B_WR|B_CS;
#endif
DDRD =0xFF;
#if DISP_TRANSFER==16
DDRB|=0x3F;
DDRC|=0x03;
#endif
}
void UTFT::fillW(word w, int r1, int r2) {
#ifdef __MPS430__ // 16-bit optimized loops
if (!r1 || !r2) return;
#define DO do {int r=r1; do // two nested loops
#define WHILE while (--r);} while(--r2)
#else // 8-bit optimized loops
unsigned long rep=(unsigned long)(word)r1*(word)r2;
if (!rep) return;
byte rep0=byte(rep);
byte rep1=byte(rep>>8);
byte rep2=byte(rep>>16); // 24 bits are sufficient here
if (rep0) rep1++;
if (rep1) rep2++;
#define DO do do do // three nested loops
#define WHILE while (--rep0); while(--rep1); while(--rep2)
#endif
#if DISP_TRANSFER==16
PORTD=w>>8;
PORTC=PORTC&0xFC|(byte)w>>6&3;
PORTB=(byte)w&0x3F;
DO pulse_low(P_WR,B_WR); WHILE;
#elif DISP_TRANSFER==8
DO{ // inline LCD_Writ_Bus() code for performance
PORTD=w>>8;
pulse_low(P_WR,B_WR);
PORTD=w;
pulse_low(P_WR,B_WR);
}WHILE;
#elif
DO LCD_Writ_Bus(w); WHILE;
#endif
#undef DO
#undef WHILE
}
void UTFT::LCD_Write_CMD_DATA(byte b,word w) {
LCD_CmdB(b);
LCD_DataW(w);
}
/*************************************
* Hardware-dependent initialization *
*************************************/
void UTFT::InitLCD(byte orientation) {
orient=orientation;
flags=0;
clrClip();
clrOrg();
//clrScale();
_set_direction_registers();
#ifdef P_RST
_delay_ms(5);
RST(0);
_delay_ms(15);
RST(1);
_delay_ms(15);
#endif
CS(0);
#ifdef disp_ILI9325D
LCD_Write_CMD_DATA(0xE5,0x78F0); // set SRAM internal timing
LCD_Write_CMD_DATA(0x01,orient<<7&0x0100); // set Driver Output Control, bit 8 reflects X counting
LCD_Write_CMD_DATA(0x02,0x0200); // set 1 line inversion
LCD_Write_CMD_DATA(0x03,0x1030);
LCD_Write_CMD_DATA(0x04,0); // Resize register
LCD_Write_CMD_DATA(0x08,0x0207); // set the back porch and front porch
LCD_Write_CMD_DATA(0x09,0); // set non-display area refresh cycle ISC[3:0]
LCD_Write_CMD_DATA(0x0A,0); // FMARK function
LCD_Write_CMD_DATA(0x0C,0); // RGB interface setting
LCD_Write_CMD_DATA(0x0D,0); // Frame marker Position
LCD_Write_CMD_DATA(0x0F,0); // RGB interface polarity
//*************Power On sequence ****************//
LCD_Write_CMD_DATA(0x10,0); // SAP, BT[3:0], AP, DSTB, SLP, STB
LCD_Write_CMD_DATA(0x11,0x0007); // DC1[2:0], DC0[2:0], VC[2:0]
LCD_Write_CMD_DATA(0x12,0); // VREG1OUT voltage
LCD_Write_CMD_DATA(0x13,0); // VDV[4:0] for VCOM amplitude
LCD_Write_CMD_DATA(0x07,0x0001);
_delay_ms(200); // Dis-charge capacitor power voltage
LCD_Write_CMD_DATA(0x10,0x1690); // SAP, BT[3:0], AP, DSTB, SLP, STB
LCD_Write_CMD_DATA(0x11,0x0227); // Set DC1[2:0], DC0[2:0], VC[2:0]
_delay_ms(50);
LCD_Write_CMD_DATA(0x12,0x000D);
_delay_ms(50);
LCD_Write_CMD_DATA(0x13,0x1200); // VDV[4:0] for VCOM amplitude
LCD_Write_CMD_DATA(0x29,0x000A); // 04 VCM[5:0] for VCOMH
LCD_Write_CMD_DATA(0x2B,0x000D); // Set Frame Rate
_delay_ms(50);
// ----------- Adjust the Gamma Curve ----------//
LCD_Write_CMD_DATA(0x30,0x0000);
LCD_Write_CMD_DATA(0x31,0x0404);
LCD_Write_CMD_DATA(0x32,0x0003);
LCD_Write_CMD_DATA(0x35,0x0405);
LCD_Write_CMD_DATA(0x36,0x0808);
LCD_Write_CMD_DATA(0x37,0x0407);
LCD_Write_CMD_DATA(0x38,0x0303);
LCD_Write_CMD_DATA(0x39,0x0707);
LCD_Write_CMD_DATA(0x3C,0x0504);
LCD_Write_CMD_DATA(0x3D,0x0808);
//------------------ Set GRAM area ---------------//
unsetWindow();
LCD_Write_CMD_DATA(0x60,0x2700|orient<<13&0x8000); // Gate Scan Line, bit 15 reflects Y counting
LCD_Write_CMD_DATA(0x61,0x0001); // NDL,VLE, REV
LCD_Write_CMD_DATA(0x6A,0); // set scrolling line
//-------------- Partial Display Control ---------//
LCD_Write_CMD_DATA(0x80,0);
LCD_Write_CMD_DATA(0x81,0);
LCD_Write_CMD_DATA(0x82,0);
LCD_Write_CMD_DATA(0x83,0);
LCD_Write_CMD_DATA(0x84,0);
LCD_Write_CMD_DATA(0x85,0);
//-------------- Panel Control -------------------//
LCD_Write_CMD_DATA(0x90,0x0010);
LCD_Write_CMD_DATA(0x92,0);
LCD_Write_CMD_DATA(0x07,0x0133); // 262K color and display ON
#else
# error "Add code here!"
#endif
CS(1);
setColor(VGA_BLACK);
setBackColor(VGA_WHITE);
}
void UTFT::lcdOff() {
CS(0);
#ifdef disp_PCF8833
LCD_CmdB(0x28);
#elifdef disp_CPLD
LCD_Write_CMD_DATA(0x01,0x0000);
LCD_CmdB(0x0F);
#endif
CS(1);
}
void UTFT::lcdOn() {
CS(0);
#ifdef disp_PCF8833
LCD_CmdB(0x29);
#elifdef disp_CPLD
LCD_Write_CMD_DATA(0x01,0x0010);
LCD_CmdB(0x0F);
#endif
CS(1);
}
void UTFT::setContrast(char c) {
CS(0);
#ifdef disp_PCF8833
if (c>64) c=64;
LCD_Write_COM(0x25);
LCD_Write_DATA(c);
#endif
CS(1);
}
void UTFT::setBrightness(byte br) {
CS(0);
#ifdef disp_CPLD
if (br>16) br=16;
LCD_Write_CMD_DATA(0x01,br);
LCD_Write_COM(0x0F);
#endif
CS(1);
}
void UTFT::setDisplayPage(byte page) {
CS(0);
#ifdef disp_CPLD
if (page>7) page=7;
LCD_Write_CMD_DATA(0x04,page);
LCD_Write_COM(0x0F);
#endif
CS(1);
}
void UTFT::setWritePage(byte page) {
CS(0);
#ifdef disp_CPLD
if (page>7) page=7;
LCD_Write_CMD_DATA(0x05,page);
LCD_Write_COM(0x0F);
#endif
CS(1);
}
/**********************************************
* Speed-optimized setpixel + bitblt routines *
**********************************************/
void UTFT::setXY(int X, int Y, bool swap) {
LCD_Write_CMD_DATA(0x20^swap,X);
LCD_Write_CMD_DATA(0x21^swap,Y);
LCD_CmdB(0x22); // prepare pixel value output
}
void UTFT::setWindow(byte o) {
byte ori=orient&1;
#ifdef disp_ILI9325D
if (o&0x80) {
if (ori) o=o&0xF9 | o<<1&4 | o>>1&2; // irgendwie müssen die Bits getauscht werden, hm...
LCD_Write_CMD_DATA(0x03,0x1030^(o&7^ori)<<3);
}
if (o&0x40) {
ori<<=1;
LCD_Write_CMD_DATA(0x50^ori,L);
LCD_Write_CMD_DATA(0x52^ori,T);
LCD_Write_CMD_DATA(0x51^ori,R);
LCD_Write_CMD_DATA(0x53^ori,B);
ori>>=1;
}
if (o&0x10) setXY(X,Y,ori); // set pixel address
#else
# error "Add code here!"
#endif
}
void UTFT::setPixel() {
if (clipOk()) {setWindow(0x30); LCD_DataW(fc);}
}
// Skips unset pixels for transparent bitblt:
// Calculates the new horizontal and vertical GRAM address
// x and y are _reversed_ _source_ coordinates
void UTFT::advance(int x,int y) {
byte o=orient>>3;
if (o&1) {
x-=H;
y-=W;
if (o&2) x+=B; else x=T-x;
if (o&4) y+=R; else y=L-y;
}else{
x-=W; // W-x = current positive x, therefore, x is now 0 or negative
y-=H;
if (o&2) x+=R; else x=L-x;
if (o&4) y+=B; else y=T-y;
}
setXY(x,y,(o^orient)&1); // don't touch current position here!!
}
void UTFT::advance() {
byte o=orient;
if (o&0x40) Y=o&0x80?(Y<<1)-YE:YE; // escapement: advance current position
else X=o&0x80?(X<<1)-XE:XE;
}
// Schwarzweiß-Version, vom Flash-Speicher, MSBfirst
// startbit = 0..7 (0 = MSB, 7 = LSB)
// Can work with very dense bitmaps (for bitmap fonts!)
// startbit is not limited to 0..7, can be any bit number
void UTFT::bitblt(const byte*data, int bitsperline, int startbit) {
if (clipX() && clipY()) {
int x=XC;
int y=YC;
if (orient&8) SWAP(x,y);
startbit+=y*bitsperline+x;
data+=startbit>>3; // correct source address
startbit&=7;
x=W;
y=H;
if (orient&8) SWAP(x,y);
bitsperline-=x; // now: bits at end of line to skip
bool skip=false;
CS(0);
setWindow(0xF0|orient>>3&7); // make clipped window current
do{
byte b=pgm_read_byte(data); // load first byte (possible multiple times!)
byte m=1<<(~startbit&7); // make first bit mask
for (int xx=x;;) {
if (flags&TRANS) {
if (b&m) {
if (skip) advance(xx,y); // set new address only at non-contiguous pixels (for more speed)
skip=false;
LCD_DataW(fc); // set pixel to foreground color at X/Y
}else skip=true;
}else LCD_DataW(b&m?fc:bc); // set pixel (always)
startbit++; // track bit where we are
if (!--xx) break; // end of line
m>>=1; // next bit in mask
if (!m) { // if emptied...
b=pgm_read_byte(++data); // load next byte
m=0x80; // set next mask bit (MSB)
startbit-=8; // should be 0
}
}
startbit+=bitsperline; // startbit can be 0..8 inclusive(!) at loop exit
data+=startbit>>3; // prepate for next line
startbit&=7;
}while(--y);
unsetWindow();
CS(1);
}//else drawCircle(100,100,80);
advance();
}
// HiColor-Version, vom Massenspeicher (Live-JPG-Dekompressor?)
void UTFT::bitblt(FILE*f, int wordsperline) {
if (clipX() && clipY()) {
int x=XC;
int y=YC;
if (x||y) {
if (orient&8) SWAP(x,y);
myseek(f,y*wordsperline+x<<1); // correct source pointer
}
x=W;
y=H;
if (orient&8) SWAP(x,y);
wordsperline-=x; // now: skip words at end (should be >=0!)
wordsperline<<=1; // now: skip bytes at end
bool skip=false;
CS(0);
setWindow(0xF0|orient>>3&7); // make clipped window current
do{ // iterate over source's y (lines)
int xx=x;
do{ // iterate over source's x (pixels)
word w=mygetw(f); // cannot handle EOF here
if (flags&TRANS) {
if (w==bc) skip=true;
else{
if (skip) advance(xx,y); // set new address _only_ at non-contiguous pixels (for more speed)
skip=false;
goto w;
}
}else w: LCD_DataW(w); // set pixel (always)
}while(--xx);
if (wordsperline) myseek(f,wordsperline); // next line
}while(--y);
unsetWindow();
CS(1);
}//else drawCircle(120,120,80);
advance();
}
void UTFT::bitblt(const word*w, int wordsperline) {
FILE f;
fdev_setup_stream(&f,0,0,_FDEV_SETUP_READ|__SSTR|__SPGM);
f.len=(int)w;
bitblt(&f,wordsperline);
}
/*********************************
* Hardware-independent graphics *
*********************************/
/*==== clipping ====*/
void UTFT::setClip(int l, int t, int r, int b) {
if (flags&MOVE) {
l+=XO; t+=YO; r+=XO; b+=YO;
flags&=~MOVE;
}
if (l<0) l=0;
if (t<0) t=0;
int e=getDisplayXSize()-1;
if (r>e) r=e;
e=getDisplayYSize()-1;
if (b>e) b=e;
clip.L=l; clip.T=t; clip.R=r; clip.B=b;
}
bool UTFT::clipX() {
int o=clip.L-L;
XC=0;
if (o>0) {L=clip.L; XC=o;}
if (R>clip.R) R=clip.R;
return (W=R-L+1)>0; // new width, return true when not empty
}
bool UTFT::clipOk() const{ // checks point inside clipping area
return clip.L<=X && X<=clip.R && clip.T<=Y && Y<=clip.B;
}
/*==== position calculation ====*/
void UTFT::setOrg(int x, int y) {
if (flags&MOVE) {
XO+=x; YO+=y;
flags&=~MOVE; // one-time flag!
}else XO=x, YO=y;
}
void UTFT::gotoXY(int x,int y) {
if (flags&MOVE) {
X+=x;
Y+=y;
flags&=~MOVE; // one-time flag!
}else X=x+XO, Y=y+YO;
}
void UTFT::targetXY(int x,int y) {
if (flags&MOVE) {
XE=X+x;
YE=Y+y;
flags&=~MOVE; // one-time flag!
}else XE=x+XO, YE=y+YO;
}
void UTFT::calcRectX() {
int w=XE-X;
R=(w<0?(L=XE)+(W=-w):(L=X)+(W=w))-1; // W never negative
}
// remove a limiting bitblt window; CS must be 0
void UTFT::unsetWindow() {
L=clip.L; T=clip.T; R=clip.R; B=clip.B;
setWindow(0xC0);
}
/*==== points and lines ====*/
void UTFT::drawPixel() {
CS(0);
setPixel();
CS(1);
}
void UTFT::lineTo(int x, int y) {
targetXY(x,y);
calcRect(); // calculate W and H
if (!W) {
R=L; B+=flags&ENDPIX; goto fr;
}else if (!H) {
B=T; R+=flags&ENDPIX; fr:
fillRect(); // clip and draw
X=XE;
Y=YE;
}else{
int xs=XE<X?-1:1;
int ys=YE<Y?-1:1;
int err=W-H;
CS(0);
for(;X!=XE || Y!=YE;) {
setPixel(); // clip and draw using DISPLAY X/Y coordinate
int e2=err<<1;
if (e2+H>0) err-=H, X+=xs;
if (e2<W) err+=W, Y+=ys;
}
if (flags&ENDPIX) setPixel();
CS(1);
}
}
/*==== outline figures ====*/
void UTFT::drawRect(int x1, int y1, int x2, int y2) {
if (x1>x2) {int t=x1;x1=x2;x2=t;}
if (y1>y2) {int t=y1;y1=x2;y2=t;}
flags&=~MOVE;
drawHLine(x1,y1,x2-x1);
drawHLine(x1,y2,x2-x1);
drawVLine(x1,y1,y2-y1);
drawVLine(x2,y1,y2-y1);
}
void UTFT::drawRoundRect(int x1, int y1, int x2, int y2, int) {
if (x1>x2) {int t=x1;x1=x2;x2=t;}
if (y1>y2) {int t=y1;y1=y2;y2=t;}
if ((x2-x1)>4 && (y2-y1)>4) {
drawPixel(x1+1,y1+1);
drawPixel(x2-1,y1+1);
drawPixel(x1+1,y2-1);
drawPixel(x2-1,y2-1);
drawHLine(x1+2, y1, x2-x1-4);
drawHLine(x1+2, y2, x2-x1-4);
drawVLine(x1, y1+2, y2-y1-4);
drawVLine(x2, y1+2, y2-y1-4);
}
}
void UTFT::drawCircle(int x, int y, int radius) {
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
CS(0);
flags&=~MOVE;
setPixel(x,y+radius);
setPixel(x,y-radius);
setPixel(x+radius,y);
setPixel(x-radius,y);
while(x1 < y1) {
if (f>=0) {
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
setPixel(x+x1,y+y1);
setPixel(x-x1,y+y1);
setPixel(x+x1,y-y1);
setPixel(x-x1,y-y1);
setPixel(x+y1,y+x1);
setPixel(x-y1,y+x1);
setPixel(x+y1,y-x1);
setPixel(x-y1,y-x1);
}
CS(1);
}
void UTFT::drawPoly(const POINT*p,int n) {
gotoXY(p[n-1].x,p[n-1].y);
for (int i=0; i<n; i++) lineTo(p[i].x,p[i].y);
}
/*==== filled figures ====*/
void UTFT::fillRect() {
if (clipX() && clipY()) {
CS(0);
setWindow(0xF0); // no specific fill direction
fillW(fc,W,H);
unsetWindow();
CS(1);
}
}
void UTFT::fillRoundRect(int x1, int y1, int x2, int y2, int) {
if (x1>x2) SWAP(x1,x2);
if (y1>y2) SWAP(y1,y2);
if ((x2-x1)>4 && (y2-y1)>4) {
for (int i=0; i<((y2-y1)/2)+1; i++) {
switch(i) {
case 0:
drawHLine(x1+2, y1+i, x2-x1-4);
drawHLine(x1+2, y2-i, x2-x1-4);
break;
case 1:
drawHLine(x1+1, y1+i, x2-x1-2);
drawHLine(x1+1, y2-i, x2-x1-2);
break;
default:
drawHLine(x1, y1+i, x2-x1);
drawHLine(x1, y2-i, x2-x1);
}
}
}
}
void UTFT::fillCircle(int x, int y, int radius) {
flags&=~MOVE;
for (int y1=-radius; y1<=0; y1++)
for (int x1=-radius; x1<=0; x1++)
if (x1*x1+y1*y1 <= radius*radius) {
drawHLine(x+x1, y+y1, 2*(-x1));
drawHLine(x+x1, y-y1, 2*(-x1));
break;
}
}
void UTFT::fillScr(word color) {
CS(0);
unsetWindow();
setXY(L,T,orient);
fillW(color,DISP_X_SIZE,DISP_Y_SIZE);
CS(1);
}
/*==== character output ====*/
void UTFT::print(char c) {
if (flags&COOKED) {
if (c=='\n') {
byte o=orient;
o^=o>>3; // include font rotation and character direction
o^=o>>5&6; // include string escapement
if (o&1) { // rotated screen ^ rotated font
Y=YO;
if (o&2) X-=cfont.cy; else X+=cfont.cy;
}else{
X=XO;
if (o&4) Y-=cfont.cy; else Y+=cfont.cy;
}
return;
}
}
if ((byte)c<cfont.first || (byte)c>=cfont.first+cfont.count) c='?';
c-=cfont.first;
int bitsperline=0;
int startbit=0;
char cx=cfont.cx;
char cy=cfont.cy;
const byte*addr=cfont.bits;
if (cx<=0) { // dense propotional font
char w=0;
for (byte i=0;;) {
byte b=pgm_read_byte(addr++);
for (byte m=0; m<2; m++) {
byte n=(b&15)-cx; // width of this character
if (i==(byte)c) {
startbit=bitsperline; // take that snapshot
w=n;
}
bitsperline+=n; // sum the widths
b>>=4;
if (++i==cfont.count) goto exi;
}
}
exi: cx=w;
deb1=w;
deb2=bitsperline;
}else{
bitsperline=cfont.cx+7&~7;
addr+=(byte)c*((byte)bitsperline>>3)*cy;
}
if (orient&8) SWAP(cx,cy); // rotate target character cell (more precisely, flip on main diagonal)
if (orient&16) cx=-cx; // reflect character cell towards left
if (orient&32) cy=-cy; // reflect character cell towards top
targetWH(cx,cy);
calcRect(); // generate character cell
bitblt(addr,bitsperline,startbit);
}
void UTFT::print(const char *s) {
for(;;s++) {
char c=*s;
if (!c) break;
print(c);
}
}
void UTFT::print(const __FlashStringHelper*h) {
const char*s=(const char*)h;
for(;;s++) {
char c=pgm_read_byte(s);
if (!c) break;
print(c);
}
}
int UTFT::getTextExtent(char c) {
int ext=cfont.cx;
if (ext>0) return ext; // return constant for monospaced font
if ((byte)c<cfont.first || (byte)c+cfont.first>=cfont.count) c='?';
c-=cfont.first;
byte b=pgm_read_byte(cfont.bits+(c>>1));
if (c&1) b>>=1; // use high nibble
return (b&15)-ext; // "add" the minimum character width
}
int UTFT::getTextExtent(const char *s) {
int ext=0;
for(;;s++) {
char c=*s;
if (!c) break;
ext+=getTextExtent(c);
}
return ext;
}
int UTFT::getTextExtent(const __FlashStringHelper*h) {
int ext=0;
const char*s=(const char*)h;
for(;;s++) {
char c=pgm_read_byte(s);
if (!c) break;
ext+=getTextExtent(c);
}
return ext;
}
#ifdef DISP_PRINTF
int UTFT::sendByte(char b, FILE*f) {
return reinterpret_cast<UTFT*>(f->get)->print(b),0;
}
void UTFT::vprintf(const char*fmt,va_list args) {
FILE f;
fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
vfprintf(&f,fmt,args);
}
void UTFT::printf(const char*fmt,...) {
va_list va;
va_start(va,fmt);
vprintf(fmt,va);
va_end(va);
}
void UTFT::vprintf(const __FlashStringHelper*fmt,va_list args) {
FILE f;
fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
vfprintf_P(&f,reinterpret_cast<const char*>(fmt),args);
}
void UTFT::printf(const __FlashStringHelper*fmt,...) {
va_list va;
va_start(va,fmt);
vprintf(fmt,va);
va_end(va);
}
#endif
void UTFT::setFont(const byte*font) {
cfont.cx=pgm_read_byte(font++);
cfont.cy=pgm_read_byte(font++);
cfont.first=pgm_read_byte(font++);
cfont.count=pgm_read_byte(font++);
cfont.bits=font;
}
Detected encoding: UTF-8 | 0
|