|
/* |
|
$Id:$ |
|
|
|
ST7565 LCD library! |
|
|
|
Copyright (C) 2010 Limor Fried, Adafruit Industries |
|
|
|
This library is free software; you can redistribute it and/or |
|
modify it under the terms of the GNU Lesser General Public |
|
License as published by the Free Software Foundation; either |
|
version 2.1 of the License, or (at your option) any later version. |
|
|
|
This library is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
Lesser General Public License for more details. |
|
|
|
You should have received a copy of the GNU Lesser General Public |
|
License along with this library; if not, write to the Free Software |
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
|
|
|
// some of this code was written by <cstone@pobox.com> originally; it is in the public domain. |
|
|
|
// this source is modified for AQM1284 by kkurahashi |
|
*/ |
|
|
|
#include <stdlib.h> |
|
|
|
#include "ST7565.h" |
|
|
|
#define ST7565_STARTBYTES 1 |
|
#define _BV(bit) (1 << (bit)) |
|
|
|
|
|
unsigned char is_reversed = 0; |
|
|
|
// a handy reference to where the pages are on the screen |
|
const unsigned char pagemap[] = { 5, 4, 3, 2, 1, 0, 7, 6}; |
|
|
|
// a 5x7 font table |
|
const extern unsigned char font[]; |
|
|
|
// the memory buffer for the LCD |
|
unsigned char st7565_buffer[1024] = { |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x3, 0x7, 0xF, 0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x7F, 0x3F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x1F, 0x3F, 0x70, 0x70, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x6, 0x0, 0x0, 0x0, 0x3, 0x3, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
|
|
0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0xF, 0x7, 0x7, |
|
0x7, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xF, 0x3F, |
|
0x70, 0x60, 0x60, 0x60, 0x60, 0x30, 0x7F, 0x3F, 0x0, 0x0, 0x1F, 0x3F, 0x70, 0x60, 0x60, 0x60, |
|
0x60, 0x39, 0xFF, 0xFF, 0x0, 0x6, 0x1F, 0x39, 0x60, 0x60, 0x60, 0x60, 0x30, 0x3F, 0x7F, 0x0, |
|
0x0, 0x60, 0xFF, 0xFF, 0x60, 0x60, 0x0, 0x7F, 0x7F, 0x70, 0x60, 0x60, 0x40, 0x0, 0x7F, 0x7F, |
|
0x0, 0x0, 0x0, 0x0, 0x7F, 0x7F, 0x0, 0x0, 0x0, 0x7F, 0x7F, 0x0, 0x0, 0x60, 0xFF, 0xFF, |
|
0x60, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
|
|
0x80, 0xF8, 0xFC, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xE7, 0xE7, 0xE3, |
|
0xF3, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0x7, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, |
|
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x0, 0x0, 0x0, 0xC0, |
|
0xE0, 0x60, 0x20, 0x20, 0x60, 0xE0, 0xE0, 0xE0, 0x0, 0x0, 0x80, 0xC0, 0xE0, 0x60, 0x20, 0x60, |
|
0x60, 0xE0, 0xE0, 0xE0, 0x0, 0x0, 0x80, 0xC0, 0x60, 0x60, 0x20, 0x60, 0x60, 0xE0, 0xE0, 0x0, |
|
0x0, 0x0, 0xE0, 0xE0, 0x0, 0x0, 0x0, 0xE0, 0xE0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xE0, |
|
0x60, 0x60, 0x60, 0x60, 0xE0, 0x80, 0x0, 0x0, 0x0, 0xE0, 0xE0, 0x0, 0x0, 0x0, 0xE0, 0xE0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
|
|
0x0, 0x0, 0x0, 0x3, 0x7, 0x1F, 0x9F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xF1, 0xE3, |
|
0xE3, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0xFC, 0x7F, 0x3F, 0x3F, 0x3F, 0x3F, 0x7F, 0xFF, 0xFF, |
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0xF0, 0xE0, 0x80, 0x0, 0x0, 0x0, 0xC, |
|
0x1C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7F, 0x7F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0x7, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1C, 0xC, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
|
|
0x0, 0x7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFC, 0xF8, |
|
0xF8, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xFF, |
|
0xFF, 0x0, 0x0, 0x0, 0xFF, 0xFF, 0xE0, 0xC0, 0xC0, 0xC0, 0xFF, 0x7F, 0x0, 0x0, 0x1E, 0x7F, |
|
0xE1, 0xC0, 0xC0, 0xC0, 0xC0, 0x61, 0xFF, 0xFF, 0x0, 0x0, 0xFE, 0xFF, 0x1, 0x0, 0x0, 0x0, |
|
0xFF, 0xFF, 0x0, 0x0, 0x21, 0xF9, 0xF8, 0xDC, 0xCC, 0xCF, 0x7, 0x0, 0xC0, 0xFF, 0xFF, 0xC0, |
|
0x80, 0x0, 0xFF, 0xFF, 0xC0, 0xC0, 0x80, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0x1F, 0x7F, 0xF9, |
|
0xC8, 0xC8, 0xC8, 0xC8, 0x79, 0x39, 0x0, 0x0, 0x71, 0xF9, 0xD8, 0xCC, 0xCE, 0x47, 0x3, 0x0, |
|
|
|
0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xF8, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xC0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC0, |
|
0xC0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x80, |
|
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, |
|
0xC0, 0x80, 0x0, 0x0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, |
|
0x0, 0x0, 0xC0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0xC0, 0xC0, 0x0, 0x0, 0x0, 0x80, 0xC0, |
|
0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80, 0x0, 0x0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x0, 0x0, |
|
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, |
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,}; |
|
|
|
// reduces how much is refreshed, which speeds it up! |
|
// originally derived from Steve Evans/JCW's mod but cleaned up and |
|
// optimized |
|
// #define enablePartialUpdate |
|
|
|
#ifdef enablePartialUpdate |
|
static unsigned char xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax; |
|
#endif |
|
|
|
|
|
|
|
static void updateBoundingBox(unsigned char xmin, unsigned char ymin, unsigned char xmax, unsigned char ymax) { |
|
#ifdef enablePartialUpdate |
|
if (xmin < xUpdateMin) xUpdateMin = xmin; |
|
if (xmax > xUpdateMax) xUpdateMax = xmax; |
|
if (ymin < yUpdateMin) yUpdateMin = ymin; |
|
if (ymax > yUpdateMax) yUpdateMax = ymax; |
|
#endif |
|
} |
|
|
|
void ST7565::drawbitmap(unsigned char x, unsigned char y, |
|
const unsigned char *bitmap, unsigned char w, unsigned char h, |
|
unsigned char color) { |
|
for (unsigned char j=0; j<h; j++) { |
|
for (unsigned char i=0; i<w; i++ ) { |
|
if (pgm_read_byte(bitmap + i + (j/8)*w) & _BV(j%8)) { |
|
my_setpixel(x+i, y+j, color); |
|
} |
|
} |
|
} |
|
|
|
updateBoundingBox(x, y, x+w, y+h); |
|
} |
|
|
|
void ST7565::drawstring(unsigned char x, unsigned char line, char *c) { |
|
while (c[0] != 0) { |
|
drawchar(x, line, c[0]); |
|
c++; |
|
x += 6; // 6 pixels wide |
|
if (x + 6 >= LCDWIDTH) { |
|
x = 0; // ran out of this line |
|
line++; |
|
} |
|
if (line >= (LCDHEIGHT/8)) |
|
return; // ran out of space :( |
|
} |
|
} |
|
|
|
|
|
void ST7565::drawstring_P(unsigned char x, unsigned char line, const char *str) { |
|
while (1) { |
|
char c = pgm_read_byte(str++); |
|
if (! c) |
|
return; |
|
drawchar(x, line, c); |
|
x += 6; // 6 pixels wide |
|
if (x + 6 >= LCDWIDTH) { |
|
x = 0; // ran out of this line |
|
line++; |
|
} |
|
if (line >= (LCDHEIGHT/8)) |
|
return; // ran out of space :( |
|
} |
|
} |
|
|
|
void ST7565::drawchar(unsigned char x, unsigned char line, char c) { |
|
for (unsigned char i =0; i<5; i++ ) { |
|
st7565_buffer[x + (line*128) ] = pgm_read_byte(font+(c*5)+i); |
|
x++; |
|
} |
|
|
|
updateBoundingBox(x, line*8, x+5, line*8 + 8); |
|
} |
|
|
|
|
|
// bresenham's algorithm - thx wikpedia |
|
void ST7565::drawline(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, |
|
unsigned char color) { |
|
unsigned char steep = abs(y1 - y0) > abs(x1 - x0); |
|
if (steep) { |
|
swap(x0, y0); |
|
swap(x1, y1); |
|
} |
|
|
|
if (x0 > x1) { |
|
swap(x0, x1); |
|
swap(y0, y1); |
|
} |
|
|
|
// much faster to put the test here, since we've already sorted the points |
|
updateBoundingBox(x0, y0, x1, y1); |
|
|
|
unsigned char dx, dy; |
|
dx = x1 - x0; |
|
dy = abs(y1 - y0); |
|
|
|
int8_t err = dx / 2; |
|
int8_t ystep; |
|
|
|
if (y0 < y1) { |
|
ystep = 1; |
|
} else { |
|
ystep = -1;} |
|
|
|
for (; x0<=x1; x0++) { |
|
if (steep) { |
|
my_setpixel(y0, x0, color); |
|
} else { |
|
my_setpixel(x0, y0, color); |
|
} |
|
err -= dy; |
|
if (err < 0) { |
|
y0 += ystep; |
|
err += dx; |
|
} |
|
} |
|
} |
|
|
|
// filled rectangle |
|
void ST7565::fillrect(unsigned char x, unsigned char y, unsigned char w, unsigned char h, |
|
unsigned char color) { |
|
|
|
// stupidest version - just pixels - but fast with internal buffer! |
|
for (unsigned char i=x; i<x+w; i++) { |
|
for (unsigned char j=y; j<y+h; j++) { |
|
my_setpixel(i, j, color); |
|
} |
|
} |
|
|
|
updateBoundingBox(x, y, x+w, y+h); |
|
} |
|
|
|
// draw a rectangle |
|
void ST7565::drawrect(unsigned char x, unsigned char y, unsigned char w, unsigned char h, |
|
unsigned char color) { |
|
// stupidest version - just pixels - but fast with internal buffer! |
|
for (unsigned char i=x; i<x+w; i++) { |
|
my_setpixel(i, y, color); |
|
my_setpixel(i, y+h-1, color); |
|
} |
|
for (unsigned char i=y; i<y+h; i++) { |
|
my_setpixel(x, i, color); |
|
my_setpixel(x+w-1, i, color); |
|
} |
|
|
|
updateBoundingBox(x, y, x+w, y+h); |
|
} |
|
|
|
// draw a circle outline |
|
void ST7565::drawcircle(unsigned char x0, unsigned char y0, unsigned char r, |
|
unsigned char color) { |
|
updateBoundingBox(x0-r, y0-r, x0+r, y0+r); |
|
|
|
int8_t f = 1 - r; |
|
int8_t ddF_x = 1; |
|
int8_t ddF_y = -2 * r; |
|
int8_t x = 0; |
|
int8_t y = r; |
|
|
|
my_setpixel(x0, y0+r, color); |
|
my_setpixel(x0, y0-r, color); |
|
my_setpixel(x0+r, y0, color); |
|
my_setpixel(x0-r, y0, color); |
|
|
|
while (x<y) { |
|
if (f >= 0) { |
|
y--; |
|
ddF_y += 2; |
|
f += ddF_y; |
|
} |
|
x++; |
|
ddF_x += 2; |
|
f += ddF_x; |
|
|
|
my_setpixel(x0 + x, y0 + y, color); |
|
my_setpixel(x0 - x, y0 + y, color); |
|
my_setpixel(x0 + x, y0 - y, color); |
|
my_setpixel(x0 - x, y0 - y, color); |
|
|
|
my_setpixel(x0 + y, y0 + x, color); |
|
my_setpixel(x0 - y, y0 + x, color); |
|
my_setpixel(x0 + y, y0 - x, color); |
|
my_setpixel(x0 - y, y0 - x, color); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
void ST7565::fillcircle(unsigned char x0, unsigned char y0, unsigned char r, |
|
unsigned char color) { |
|
updateBoundingBox(x0-r, y0-r, x0+r, y0+r); |
|
|
|
int8_t f = 1 - r; |
|
int8_t ddF_x = 1; |
|
int8_t ddF_y = -2 * r; |
|
int8_t x = 0; |
|
int8_t y = r; |
|
|
|
for (unsigned char i=y0-r; i<=y0+r; i++) { |
|
my_setpixel(x0, i, color); |
|
} |
|
|
|
while (x<y) { |
|
if (f >= 0) { |
|
y--; |
|
ddF_y += 2; |
|
f += ddF_y; |
|
} |
|
x++; |
|
ddF_x += 2; |
|
f += ddF_x; |
|
|
|
for (unsigned char i=y0-y; i<=y0+y; i++) { |
|
my_setpixel(x0+x, i, color); |
|
my_setpixel(x0-x, i, color); |
|
} |
|
for (unsigned char i=y0-x; i<=y0+x; i++) { |
|
my_setpixel(x0+y, i, color); |
|
my_setpixel(x0-y, i, color); |
|
} |
|
} |
|
} |
|
|
|
void ST7565::my_setpixel(unsigned char x, unsigned char y, unsigned char color) { |
|
if ((x >= LCDWIDTH) || (y >= LCDHEIGHT)) |
|
return; |
|
|
|
// x is which column |
|
if (color) |
|
st7565_buffer[x+ (y/8)*128] |= _BV(7-(y%8)); |
|
else |
|
st7565_buffer[x+ (y/8)*128] &= ~_BV(7-(y%8)); |
|
} |
|
|
|
// the most basic function, set a single pixel |
|
void ST7565::setpixel(unsigned char x, unsigned char y, unsigned char color) { |
|
if ((x >= LCDWIDTH) || (y >= LCDHEIGHT)) |
|
return; |
|
|
|
// x is which column |
|
if (color) |
|
st7565_buffer[x+ (y/8)*128] |= _BV(7-(y%8)); |
|
else |
|
st7565_buffer[x+ (y/8)*128] &= ~_BV(7-(y%8)); |
|
|
|
updateBoundingBox(x,y,x,y); |
|
} |
|
|
|
|
|
// the most basic function, get a single pixel |
|
unsigned char ST7565::getpixel(unsigned char x, unsigned char y) { |
|
if ((x >= LCDWIDTH) || (y >= LCDHEIGHT)) |
|
return 0; |
|
|
|
return (st7565_buffer[x+ (y/8)*128] >> (7-(y%8))) & 0x1; |
|
} |
|
|
|
void ST7565::begin(unsigned char contrast) { |
|
st7565_init(); |
|
st7565_command(CMD_DISPLAY_ON); |
|
st7565_command(CMD_SET_ALLPTS_NORMAL); |
|
st7565_set_brightness(contrast); |
|
} |
|
|
|
void ST7565::st7565_init(void) { |
|
// set pin directions |
|
pinMode(sid, OUTPUT); |
|
pinMode(sclk, OUTPUT); |
|
pinMode(a0, OUTPUT); |
|
pinMode(rst, OUTPUT); |
|
pinMode(cs, OUTPUT); |
|
|
|
// toggle RST low to reset; CS low so it'll listen to us |
|
if (cs > 0) |
|
digitalWrite(cs, LOW); |
|
|
|
digitalWrite(rst, LOW); |
|
delay(500); |
|
digitalWrite(rst, HIGH); |
|
|
|
// LCD bias select |
|
st7565_command(CMD_SET_BIAS_7); |
|
// ADC select |
|
st7565_command(CMD_SET_ADC_NORMAL); |
|
// SHL select |
|
st7565_command(CMD_SET_COM_NORMAL); |
|
// Initial display line |
|
st7565_command(CMD_SET_DISP_START_LINE); |
|
|
|
// turn on voltage converter (VC=1, VR=0, VF=0) |
|
st7565_command(CMD_SET_POWER_CONTROL | 0x4); |
|
// wait for 50% rising |
|
delay(50); |
|
|
|
// turn on voltage regulator (VC=1, VR=1, VF=0) |
|
st7565_command(CMD_SET_POWER_CONTROL | 0x6); |
|
// wait >=50ms |
|
delay(50); |
|
|
|
// turn on voltage follower (VC=1, VR=1, VF=1) |
|
st7565_command(CMD_SET_POWER_CONTROL | 0x7); |
|
// wait |
|
delay(10); |
|
|
|
// set lcd operating voltage (regulator resistor, ref voltage resistor) |
|
st7565_command(CMD_SET_RESISTOR_RATIO | 0x6); |
|
|
|
// initial display line |
|
// set page address |
|
// set column address |
|
// write display data |
|
|
|
// set up a bounding box for screen updates |
|
|
|
updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); |
|
} |
|
|
|
inline void ST7565::spiwrite(unsigned char c) { |
|
shiftOut(sid, sclk, MSBFIRST, c); |
|
/* |
|
int8_t i; |
|
for (i=7; i>=0; i--) { |
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(i)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
} |
|
*/ |
|
|
|
/* |
|
// loop unwrapped! too fast doesnt work :( |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(7)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(6)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(5)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(4)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(3)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(2)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(1)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
|
|
SCLK_PORT &= ~_BV(SCLK); |
|
if (c & _BV(0)) |
|
SID_PORT |= _BV(SID); |
|
else |
|
SID_PORT &= ~_BV(SID); |
|
SCLK_PORT |= _BV(SCLK); |
|
*/ |
|
|
|
} |
|
void ST7565::st7565_command(unsigned char c) { |
|
digitalWrite(a0, LOW); |
|
|
|
spiwrite(c); |
|
} |
|
|
|
void ST7565::st7565_data(unsigned char c) { |
|
digitalWrite(a0, HIGH); |
|
|
|
spiwrite(c); |
|
} |
|
void ST7565::st7565_set_brightness(unsigned char val) { |
|
st7565_command(0x23); // Vo voltage resistor ratio set |
|
st7565_command(CMD_SET_VOLUME_FIRST); |
|
st7565_command(CMD_SET_VOLUME_SECOND | (val & 0x3f)); |
|
} |
|
|
|
|
|
void ST7565::display(void) { |
|
unsigned char col, maxcol, p; |
|
|
|
/* |
|
Serial.print("Refresh ("); Serial.print(xUpdateMin, DEC); |
|
Serial.print(", "); Serial.print(xUpdateMax, DEC); |
|
Serial.print(","); Serial.print(yUpdateMin, DEC); |
|
Serial.print(", "); Serial.print(yUpdateMax, DEC); Serial.println(")"); |
|
*/ |
|
|
|
for(p = 0; p < 8; p++) { |
|
/* |
|
putstring("new page! "); |
|
uart_putw_dec(p); |
|
putstring_nl(""); |
|
*/ |
|
#ifdef enablePartialUpdate |
|
// check if this page is part of update |
|
if ( yUpdateMin >= ((p+1)*8) ) { |
|
continue; // nope, skip it! |
|
} |
|
if (yUpdateMax < p*8) { |
|
break; |
|
} |
|
#endif |
|
|
|
st7565_command(CMD_SET_PAGE | pagemap[p]); |
|
|
|
|
|
#ifdef enablePartialUpdate |
|
col = xUpdateMin; |
|
maxcol = xUpdateMax; |
|
#else |
|
// start at the beginning of the row |
|
col = 0; |
|
maxcol = LCDWIDTH-1; |
|
#endif |
|
|
|
st7565_command(CMD_SET_COLUMN_LOWER | ((col+ST7565_STARTBYTES) & 0xf)); |
|
st7565_command(CMD_SET_COLUMN_UPPER | (((col+ST7565_STARTBYTES) >> 4) & 0x0F)); |
|
st7565_command(CMD_RMW); |
|
|
|
for(; col <= maxcol; col++) { |
|
//uart_putw_dec(col); |
|
//uart_putchar(' '); |
|
st7565_data(st7565_buffer[(128*p)+col]); |
|
} |
|
} |
|
|
|
#ifdef enablePartialUpdate |
|
xUpdateMin = LCDWIDTH - 1; |
|
xUpdateMax = 0; |
|
yUpdateMin = LCDHEIGHT-1; |
|
yUpdateMax = 0; |
|
#endif |
|
} |
|
|
|
// clear everything |
|
void ST7565::clear(void) { |
|
memset(st7565_buffer, 0, 1024); |
|
updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); |
|
} |
|
|
|
|
|
// this doesnt touch the buffer, just clears the display RAM - might be handy |
|
void ST7565::clear_display(void) { |
|
unsigned char p, c; |
|
|
|
for(p = 0; p < 8; p++) { |
|
/* |
|
putstring("new page! "); |
|
uart_putw_dec(p); |
|
putstring_nl(""); |
|
*/ |
|
|
|
st7565_command(CMD_SET_PAGE | p); |
|
for(c = 0; c < 129; c++) { |
|
//uart_putw_dec(c); |
|
//uart_putchar(' '); |
|
st7565_command(CMD_SET_COLUMN_LOWER | (c & 0xf)); |
|
st7565_command(CMD_SET_COLUMN_UPPER | ((c >> 4) & 0xf)); |
|
st7565_data(0x0); |
|
} |
|
} |
|
} |