ATMega 328p ILI9341 TFT Library
22 September, 2017
Have at it.
#define ClearBit(x,y) x &= ~_BV(y)
#define SetBit(x,y) x |= _BV(y)
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define SLPOUT 0x11 // sleep out
#define DISPON 0x29 // display on
#define CASET 0x2A // column address set
#define RASET 0x2B // row address set
#define RAMWR 0x2C // RAM write
#define COLMOD 0x3A // color mode
#define MADCTL 0x36 // axis control
// Color constants
#define BLACK 0x0000
#define RED 0x001F
#define BLUE 0xF800
#define GREEN 0x0400
typedef uint8_t byte;
typedef int8_t sbyte;
const byte FONT_CHARS[96][5] PROGMEM =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00 }, // (space)
{ 0x00, 0x00, 0x5F, 0x00, 0x00 }, // !
{ 0x00, 0x07, 0x00, 0x07, 0x00 }, // "
{ 0x14, 0x7F, 0x14, 0x7F, 0x14 }, // #
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12 }, // $
{ 0x23, 0x13, 0x08, 0x64, 0x62 }, // %
{ 0x36, 0x49, 0x55, 0x22, 0x50 }, // &
{ 0x00, 0x05, 0x03, 0x00, 0x00 }, // '
{ 0x00, 0x1C, 0x22, 0x41, 0x00 }, // (
{ 0x00, 0x41, 0x22, 0x1C, 0x00 }, // )
{ 0x08, 0x2A, 0x1C, 0x2A, 0x08 }, // *
{ 0x08, 0x08, 0x3E, 0x08, 0x08 }, // +
{ 0x00, 0x50, 0x30, 0x00, 0x00 }, // ,
{ 0x08, 0x08, 0x08, 0x08, 0x08 }, // -
{ 0x00, 0x60, 0x60, 0x00, 0x00 }, // .
{ 0x20, 0x10, 0x08, 0x04, 0x02 }, // /
{ 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0
{ 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1
{ 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2
{ 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3
{ 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4
{ 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5
{ 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6
{ 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7
{ 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8
{ 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9
{ 0x00, 0x36, 0x36, 0x00, 0x00 }, // :
{ 0x00, 0x56, 0x36, 0x00, 0x00 }, // ;
{ 0x00, 0x08, 0x14, 0x22, 0x41 }, // <
{ 0x14, 0x14, 0x14, 0x14, 0x14 }, // =
{ 0x41, 0x22, 0x14, 0x08, 0x00 }, // >
{ 0x02, 0x01, 0x51, 0x09, 0x06 }, // ?
{ 0x32, 0x49, 0x79, 0x41, 0x3E }, // @
{ 0x7E, 0x11, 0x11, 0x11, 0x7E }, // A
{ 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B
{ 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C
{ 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D
{ 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E
{ 0x7F, 0x09, 0x09, 0x01, 0x01 }, // F
{ 0x3E, 0x41, 0x41, 0x51, 0x32 }, // G
{ 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H
{ 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I
{ 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J
{ 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K
{ 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L
{ 0x7F, 0x02, 0x04, 0x02, 0x7F }, // M
{ 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N
{ 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O
{ 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P
{ 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q
{ 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R
{ 0x46, 0x49, 0x49, 0x49, 0x31 }, // S
{ 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T
{ 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U
{ 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V
{ 0x7F, 0x20, 0x18, 0x20, 0x7F }, // W
{ 0x63, 0x14, 0x08, 0x14, 0x63 }, // X
{ 0x03, 0x04, 0x78, 0x04, 0x03 }, // Y
{ 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z
{ 0x00, 0x00, 0x7F, 0x41, 0x41 }, // [
{ 0x02, 0x04, 0x08, 0x10, 0x20 }, // "\"
{ 0x41, 0x41, 0x7F, 0x00, 0x00 }, // ]
{ 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^
{ 0x40, 0x40, 0x40, 0x40, 0x40 }, // _
{ 0x00, 0x01, 0x02, 0x04, 0x00 }, // `
{ 0x20, 0x54, 0x54, 0x54, 0x78 }, // a
{ 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b
{ 0x38, 0x44, 0x44, 0x44, 0x20 }, // c
{ 0x38, 0x44, 0x44, 0x48, 0x7F }, // d
{ 0x38, 0x54, 0x54, 0x54, 0x18 }, // e
{ 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f
{ 0x08, 0x14, 0x54, 0x54, 0x3C }, // g
{ 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h
{ 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i
{ 0x20, 0x40, 0x44, 0x3D, 0x00 }, // j
{ 0x00, 0x7F, 0x10, 0x28, 0x44 }, // k
{ 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l
{ 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m
{ 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n
{ 0x38, 0x44, 0x44, 0x44, 0x38 }, // o
{ 0x7C, 0x14, 0x14, 0x14, 0x08 }, // p
{ 0x08, 0x14, 0x14, 0x18, 0x7C }, // q
{ 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r
{ 0x48, 0x54, 0x54, 0x54, 0x20 }, // s
{ 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t
{ 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u
{ 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v
{ 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w
{ 0x44, 0x28, 0x10, 0x28, 0x44 }, // x
{ 0x0C, 0x50, 0x50, 0x50, 0x3C }, // y
{ 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z
{ 0x00, 0x08, 0x36, 0x41, 0x00 }, // {
{ 0x00, 0x00, 0x7F, 0x00, 0x00 }, // |
{ 0x00, 0x41, 0x36, 0x08, 0x00 }, // }
{ 0x08, 0x08, 0x2A, 0x1C, 0x08 }, // ->
{ 0x08, 0x1C, 0x2A, 0x08, 0x08 }, // <-
};
void SetupPorts()
{
DDRB = 0x2F; // set B0-B3, B5 as outputs
DDRC = 0x00; // set PORTC as inputs
DDRD |= (1<<DDD7);
SetBit(PORTB,0); //Reset low
}
void OpenSPI()
{
SPCR = 0x50; // SPI enabled at 4 MHz
SetBit(SPSR,SPI2X); // double SPI rate
}
byte Xfer(byte data)
{
SPDR = data; // initiate transfer
while (!(SPSR & 0x80)); // wait for transfer
return SPDR;
}
void WriteCmd (byte cmd)
{
ClearBit(PORTD,7);
Xfer(cmd);
SetBit(PORTD,7);
}
void WriteByte (byte b)
{
Xfer(b);
}
void WriteWord (int w)
{
Xfer(w >> 8); // write upper 8 bits
Xfer(w & 0xFF); // write lower 8 bits
}
void Write565 (int data, unsigned long count)
{
WriteCmd(RAMWR);
while (count>0)
{
SPDR = (data >> 8); // write hi byte
while (!(SPSR & 0x80)); // wait for transfer to complete
SPDR = (data & 0xFF); // write lo byte
while (!(SPSR & 0x80)); // wait for transfer to complete
count--;
}
}
void HReset()
{
ClearBit(PORTB,0); // pull PB0 (digital 8) low
SetBit(PORTB,0); // return PB0 high
}
void InitDisplay()
{
HReset(); // initialize display controller
WriteCmd(SLPOUT); // take display out of sleep mode
WriteCmd(COLMOD); // select color mode:
WriteByte(0x05); // mode 5 = 16bit pixels (RGB565)
WriteCmd(DISPON); // turn display on!
}
void SetAddrWindow(int x0, int y0, int x1, int y1)
{
WriteCmd(CASET); // set column range (x0,x1)
WriteWord(x0);
WriteWord(x1);
WriteCmd(RASET); // set row range (y0,y1)
WriteWord(y0);
WriteWord(y1);
}
void DrawPixel (int x, int y, int color)
{
SetAddrWindow(x,y,x,y);
Write565(color,1);
}
void drawVLine(int xo, int yo, int y, int color)
{
int i=y;
while (i>yo)
{
DrawPixel(i,xo,color);
i--;
}
}
void drawHLine(int yo, int xo, int x, int color)
{
int i=x;
while (i>xo)
{
DrawPixel(yo,i,color);
i--;
}
}
void Rectangle(int x, int y, int x_size, int y_size, int color)
{
int yend= y - y_size;
int xend= x - x_size;
int thickness=2;
int i=0;
while (i<thickness)
{
drawHLine(y+i, xend, x, color);
drawHLine(yend-i, xend, x, color);
i++;
}
i=0;
while (i<thickness)
{
drawVLine(x+i, yend, y, color);
drawVLine(xend-i, yend, y, color);
i++;
}
i=0;
}
void drawdatabox()
{
Rectangle(310, 230, 130, 50, GREEN);
}
void SetOrientation(int degrees)
// Set the display orientation to 0,90,180,or 270 degrees
{
byte arg;
switch (degrees)
{
case 90: arg = 0x60; break;
case 180: arg = 0xC0; break;
case 270: arg = 0xA0; break;
default: arg = 0x00; break;
}
WriteCmd(MADCTL);
WriteByte(arg);
}
void PutCh (char ch, long x, long y, int color)
{
int pixel;
byte row, col, bit, data, mask = 0x40;
SetAddrWindow(x,y,x+4,y+6);
WriteCmd(RAMWR);
for (row=0; row<7;row++)
{
for (col=0; col<5;col++)
{
data = pgm_read_byte(&(FONT_CHARS[ch-32][col]));
bit = data & mask;
if (bit==0) pixel=BLACK;
else pixel=color;
WriteWord(pixel);
}
mask >>= 1;
}
}
long curX,curY; // current x & y cursor position
void GotoXY (long x,long y)
// position cursor on character x,y grid, where 0<x<20, 0<y<19.
{
curX = x;
curY = y;
}
void GotoLine(long y)
// position character cursor to start of line y, where 0<y<19.
{
curX = 0;
curY = y;
}
void AdvanceCursor()
// moves character cursor to next position, assuming portrait orientation
{
curX=curX+6; // advance x position
}
void WriteChar(char ch, int color)
// writes character to display at current cursor position.
{
PutCh(ch,curX, curY, color);
AdvanceCursor();
}
void WriteString(char *text, int color)
// writes string to display at current cursor position.
{
for (;*text;text++) // for all non-nul chars
WriteChar(*text,color); // write the char
}
void WriteInt(int i, int color)
// writes integer i at current cursor position
{
char str[8]; // buffer for string result
itoa(i,str,10); // convert to string, base 10
WriteString(str,color);
}
void blankscreen()
{
SetOrientation(0);
int i=0;
int j=0;
while(i<320)
{
while(j<240)
{
DrawPixel(j,i,BLACK);
j++;
}
j=0;
i++;
}
}