Merge gpanel branch.

This commit is contained in:
Serge Vakulenko
2015-10-31 21:12:50 -07:00
parent e00196ee21
commit abcfb06b0b
6 changed files with 0 additions and 1885 deletions

View File

@@ -1,579 +0,0 @@
// IMPORTANT: LIBRARY MUST BE SPECIFICALLY CONFIGURED FOR EITHER TFT SHIELD
// OR BREAKOUT BOARD USAGE. SEE RELEVANT COMMENTS IN Adafruit_ILI9341_8bit_AS.h
// Graphics library by ladyada/adafruit with init code from Rossum
// MIT license
#include <avr/pgmspace.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include "Adafruit_ILI9341_8bit_AS.h"
#if defined __AVR_ATmega328P__
#include "pin_magic_UNO.h"
#endif
#if defined __AVR_ATmega2560__
#include "pin_magic_MEGA.h"
#endif
//#define TFTWIDTH 320
//#define TFTHEIGHT 480
#define TFTWIDTH 240
#define TFTHEIGHT 320
// LCD controller chip identifiers
#define ID_9341 2
#include "registers.h"
// Constructor for breakout board (configurable LCD control lines).
// Can still use this w/shield, but parameters are ignored.
Adafruit_ILI9341_8bit_AS::Adafruit_ILI9341_8bit_AS(uint8_t cs, uint8_t cd, uint8_t wr, uint8_t rd, uint8_t reset) : Adafruit_GFX_AS(TFTWIDTH, TFTHEIGHT) {
#ifndef USE_ADAFRUIT_SHIELD_PINOUT
// Convert pin numbers to registers and bitmasks
_reset = reset;
csPort = portOutputRegister(digitalPinToPort(cs));
cdPort = portOutputRegister(digitalPinToPort(cd));
wrPort = portOutputRegister(digitalPinToPort(wr));
rdPort = portOutputRegister(digitalPinToPort(rd));
csPinSet = digitalPinToBitMask(cs);
cdPinSet = digitalPinToBitMask(cd);
wrPinSet = digitalPinToBitMask(wr);
rdPinSet = digitalPinToBitMask(rd);
csPinUnset = ~csPinSet;
cdPinUnset = ~cdPinSet;
wrPinUnset = ~wrPinSet;
rdPinUnset = ~rdPinSet;
*csPort |= csPinSet; // Set all control bits to HIGH (idle)
*cdPort |= cdPinSet; // Signals are ACTIVE LOW
*wrPort |= wrPinSet;
*rdPort |= rdPinSet;
pinMode(cs, OUTPUT); // Enable outputs
pinMode(cd, OUTPUT);
pinMode(wr, OUTPUT);
pinMode(rd, OUTPUT);
if(reset) {
digitalWrite(reset, HIGH);
pinMode(reset, OUTPUT);
}
#endif
init();
}
// Constructor for shield (fixed LCD control lines)
Adafruit_ILI9341_8bit_AS::Adafruit_ILI9341_8bit_AS(void) : Adafruit_GFX_AS(TFTWIDTH, TFTHEIGHT) {
init();
}
// Initialization common to both shield & breakout configs
void Adafruit_ILI9341_8bit_AS::init(void) {
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
CS_IDLE; // Set all control bits to idle state
WR_IDLE;
RD_IDLE;
CD_DATA;
digitalWrite(5, HIGH); // Reset line
pinMode(A3, OUTPUT); // Enable outputs
pinMode(A2, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A0, OUTPUT);
pinMode( 5, OUTPUT);
#endif
setWriteDir(); // Set up LCD data port(s) for WRITE operations
rotation = 0;
cursor_y = cursor_x = 0;
textsize = 1;
textcolor = 0xFFFF;
_width = TFTWIDTH;
_height = TFTHEIGHT;
}
// Initialization command tables for different LCD controllers
#define ILI9341_8bit_AS_DELAY 0xFF
static const uint8_t HX8347G_regValues[] PROGMEM = {
0x2E , 0x89,
0x29 , 0x8F,
0x2B , 0x02,
0xE2 , 0x00,
0xE4 , 0x01,
0xE5 , 0x10,
0xE6 , 0x01,
0xE7 , 0x10,
0xE8 , 0x70,
0xF2 , 0x00,
0xEA , 0x00,
0xEB , 0x20,
0xEC , 0x3C,
0xED , 0xC8,
0xE9 , 0x38,
0xF1 , 0x01,
// skip gamma, do later
0x1B , 0x1A,
0x1A , 0x02,
0x24 , 0x61,
0x25 , 0x5C,
0x18 , 0x36,
0x19 , 0x01,
0x1F , 0x88,
ILI9341_8bit_AS_DELAY , 5 , // delay 5 ms
0x1F , 0x80,
ILI9341_8bit_AS_DELAY , 5 ,
0x1F , 0x90,
ILI9341_8bit_AS_DELAY , 5 ,
0x1F , 0xD4,
ILI9341_8bit_AS_DELAY , 5 ,
0x17 , 0x05,
0x36 , 0x09,
0x28 , 0x38,
ILI9341_8bit_AS_DELAY , 40 ,
0x28 , 0x3C,
0x02 , 0x00,
0x03 , 0x00,
0x04 , 0x00,
0x05 , 0xEF,
0x06 , 0x00,
0x07 , 0x00,
0x08 , 0x01,
0x09 , 0x3F
};
void Adafruit_ILI9341_8bit_AS::begin(uint16_t id) {
uint8_t i = 0;
reset();
delay(200);
uint16_t a, d;
driver = ID_9341;
CS_ACTIVE;
writeRegister8(ILI9341_SOFTRESET, 0);
delay(50);
writeRegister8(ILI9341_DISPLAYOFF, 0);
writeRegister8(ILI9341_POWERCONTROL1, 0x23);
writeRegister8(ILI9341_POWERCONTROL2, 0x10);
writeRegister16(ILI9341_VCOMCONTROL1, 0x2B2B);
writeRegister8(ILI9341_VCOMCONTROL2, 0xC0);
writeRegister8(ILI9341_MEMCONTROL, ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR);
writeRegister8(ILI9341_PIXELFORMAT, 0x55);
writeRegister16(ILI9341_FRAMECONTROL, 0x001B);
writeRegister8(ILI9341_ENTRYMODE, 0x07);
/* writeRegister32(ILI9341_DISPLAYFUNC, 0x0A822700);*/
writeRegister8(ILI9341_SLEEPOUT, 0);
delay(150);
writeRegister8(ILI9341_DISPLAYON, 0);
delay(500);
setAddrWindow(0, 0, TFTWIDTH-1, TFTHEIGHT-1);
return;
}
void Adafruit_ILI9341_8bit_AS::reset(void) {
CS_IDLE;
// CD_DATA;
WR_IDLE;
RD_IDLE;
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
digitalWrite(5, LOW);
delay(2);
digitalWrite(5, HIGH);
#else
// if we have a reset pin defined ( _reset )
if(_reset) {
digitalWrite(_reset, LOW);
delay(2);
digitalWrite(_reset, HIGH);
}
#endif
// Data transfer sync
CS_ACTIVE;
CD_COMMAND;
write8(0x00);
for(uint8_t i=0; i<3; i++) WR_STROBE; // Three extra 0x00s
CS_IDLE;
// let the display recover from the reset
delay(500);
}
// Sets the LCD address window (and address counter, on 932X).
// Relevant to rect/screen fills and H/V lines. Input coordinates are
// assumed pre-sorted (e.g. x2 >= x1).
void Adafruit_ILI9341_8bit_AS::setAddrWindow(int x1, int y1, int x2, int y2) {
CS_ACTIVE;
uint32_t t;
t = x1;
t <<= 16;
t |= x2;
writeRegister32(ILI9341_COLADDRSET, t); // HX8357D uses same registers!
t = y1;
t <<= 16;
t |= y2;
writeRegister32(ILI9341_PAGEADDRSET, t); // HX8357D uses same registers!
CS_IDLE;
}
// Fast block fill operation for fillScreen, fillRect, H/V line, etc.
// Requires setAddrWindow() has previously been called to set the fill
// bounds. 'len' is inclusive, MUST be >= 1.
void Adafruit_ILI9341_8bit_AS::flood(uint16_t color, uint32_t len) {
uint16_t blocks;
uint8_t i, hi = color >> 8,
lo = color;
CS_ACTIVE;
CD_COMMAND;
write8(0x2C);
// Write first pixel normally, decrement counter by 1
CD_DATA;
write8(hi);
write8(lo);
len--;
blocks = (uint16_t)(len / 64); // 64 pixels/block
if(hi == lo) {
// High and low bytes are identical. Leave prior data
// on the port(s) and just toggle the write strobe.
while(blocks--) {
i = 16; // 64 pixels/block / 4 pixels/pass
do {
WR_STROBE; WR_STROBE; WR_STROBE; WR_STROBE; // 2 bytes/pixel
WR_STROBE; WR_STROBE; WR_STROBE; WR_STROBE; // x 4 pixels
} while(--i);
}
// Fill any remaining pixels (1 to 64)
for(i = (uint8_t)len & 63; i--; ) {
WR_STROBE;
WR_STROBE;
}
} else {
while(blocks--) {
i = 16; // 64 pixels/block / 4 pixels/pass
do {
write8(hi); write8(lo); write8(hi); write8(lo);
write8(hi); write8(lo); write8(hi); write8(lo);
} while(--i);
}
for(i = (uint8_t)len & 63; i--; ) {
write8(hi);
write8(lo);
}
}
CS_IDLE;
}
void Adafruit_ILI9341_8bit_AS::drawFastHLine(int16_t x, int16_t y, int16_t length,
uint16_t color)
{
int16_t x2;
// Initial off-screen clipping
if((length <= 0 ) ||
(y < 0 ) || ( y >= _height) ||
(x >= _width) || ((x2 = (x+length-1)) < 0 )) return;
if(x < 0) { // Clip left
length += x;
x = 0;
}
if(x2 >= _width) { // Clip right
x2 = _width - 1;
length = x2 - x + 1;
}
setAddrWindow(x, y, x2, y);
flood(color, length);
}
void Adafruit_ILI9341_8bit_AS::drawFastVLine(int16_t x, int16_t y, int16_t length,
uint16_t color)
{
int16_t y2;
// Initial off-screen clipping
if((length <= 0 ) ||
(x < 0 ) || ( x >= _width) ||
(y >= _height) || ((y2 = (y+length-1)) < 0 )) return;
if(y < 0) { // Clip top
length += y;
y = 0;
}
if(y2 >= _height) { // Clip bottom
y2 = _height - 1;
length = y2 - y + 1;
}
setAddrWindow(x, y, x, y2);
flood(color, length);
}
void Adafruit_ILI9341_8bit_AS::fillRect(int16_t x1, int16_t y1, int16_t w, int16_t h,
uint16_t fillcolor) {
int16_t x2, y2;
// Initial off-screen clipping
if( (w <= 0 ) || (h <= 0 ) ||
(x1 >= _width) || (y1 >= _height) ||
((x2 = x1+w-1) < 0 ) || ((y2 = y1+h-1) < 0 )) return;
if(x1 < 0) { // Clip left
w += x1;
x1 = 0;
}
if(y1 < 0) { // Clip top
h += y1;
y1 = 0;
}
if(x2 >= _width) { // Clip right
x2 = _width - 1;
w = x2 - x1 + 1;
}
if(y2 >= _height) { // Clip bottom
y2 = _height - 1;
h = y2 - y1 + 1;
}
setAddrWindow(x1, y1, x2, y2);
flood(fillcolor, (uint32_t)w * (uint32_t)h);
}
void Adafruit_ILI9341_8bit_AS::fillScreen(uint16_t color) {
// For these, there is no settable address pointer, instead the
// address window must be set for each drawing operation. However,
// this display takes rotation into account for the parameters, no
// need to do extra rotation math here.
setAddrWindow(0, 0, _width - 1, _height - 1);
flood(color, (long)TFTWIDTH * (long)TFTHEIGHT);
}
void Adafruit_ILI9341_8bit_AS::drawPixel(int16_t x, int16_t y, uint16_t color) {
// Clip
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
CS_ACTIVE;
setAddrWindow(x, y, _width-1, _height-1);
CS_ACTIVE;
CD_COMMAND;
write8(0x2C);
CD_DATA;
write8(color >> 8); write8(color);
CS_IDLE;
}
// Issues 'raw' an array of 16-bit color values to the LCD; used
// externally by BMP examples. Assumes that setWindowAddr() has
// previously been set to define the bounds. Max 255 pixels at
// a time (BMP examples read in small chunks due to limited RAM).
void Adafruit_ILI9341_8bit_AS::pushColors(uint16_t *data, uint8_t len, boolean first) {
uint16_t color;
uint8_t hi, lo;
CS_ACTIVE;
if(first == true) { // Issue GRAM write command only on first call
CD_COMMAND;
write8(0x2C);
}
CD_DATA;
while(len--) {
color = *data++;
hi = color >> 8; // Don't simplify or merge these
lo = color; // lines, there's macro shenanigans
write8(hi); // going on.
write8(lo);
}
CS_IDLE;
}
void Adafruit_ILI9341_8bit_AS::setRotation(uint8_t x) {
// Call parent rotation func first -- sets up rotation flags, etc.
Adafruit_GFX_AS::setRotation(x);
// Then perform hardware-specific rotation operations...
CS_ACTIVE;
uint16_t t;
switch (rotation) {
case 2:
t = ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR;
break;
case 3:
t = ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR;
break;
case 0:
t = ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR;
break;
case 1:
t = ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR;
break;
}
writeRegister8(ILI9341_MADCTL, t ); // MADCTL
// For 9341, init default full-screen address window:
setAddrWindow(0, 0, _width - 1, _height - 1); // CS_IDLE happens here
writeRegister8(ILI9341_MADCTL, t ); // MADCTL
// For 8357, init default full-screen address window:
setAddrWindow(0, 0, _width - 1, _height - 1); // CS_IDLE happens here
}
#ifdef read8isFunctionalized
#define read8(x) x=read8fn()
#endif
// Because this function is used infrequently, it configures the ports for
// the read operation, reads the data, then restores the ports to the write
// configuration. Write operations happen a LOT, so it's advantageous to
// leave the ports in that state as a default.
uint16_t Adafruit_ILI9341_8bit_AS::readPixel(int16_t x, int16_t y) {
return 0;
}
// Ditto with the read/write port directions, as above.
uint16_t Adafruit_ILI9341_8bit_AS::readID(void) {
uint16_t id = readReg(0xD3);
return id;
}
uint32_t Adafruit_ILI9341_8bit_AS::readReg(uint8_t r) {
uint32_t id;
uint8_t x;
// try reading register #4
CS_ACTIVE;
CD_COMMAND;
write8(r);
setReadDir(); // Set up LCD data port(s) for READ operations
CD_DATA;
delayMicroseconds(50);
read8(x);
id = x; // Do not merge or otherwise simplify
id <<= 8; // these lines. It's an unfortunate
read8(x);
id |= x; // shenanigans that are going on.
id <<= 8; // these lines. It's an unfortunate
read8(x);
id |= x; // shenanigans that are going on.
id <<= 8; // these lines. It's an unfortunate
read8(x);
id |= x; // shenanigans that are going on.
CS_IDLE;
setWriteDir(); // Restore LCD data port(s) to WRITE configuration
return id;
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t Adafruit_ILI9341_8bit_AS::color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
// For I/O macros that were left undefined, declare function
// versions that reference the inline macros just once:
#ifndef write8
void Adafruit_ILI9341_8bit_AS::write8(uint8_t value) {
write8inline(value);
}
#endif
#ifdef read8isFunctionalized
uint8_t Adafruit_ILI9341_8bit_AS::read8fn(void) {
uint8_t result;
read8inline(result);
return result;
}
#endif
#ifndef setWriteDir
void Adafruit_ILI9341_8bit_AS::setWriteDir(void) {
setWriteDirInline();
}
#endif
#ifndef setReadDir
void Adafruit_ILI9341_8bit_AS::setReadDir(void) {
setReadDirInline();
}
#endif
#ifndef writeRegister8
void Adafruit_ILI9341_8bit_AS::writeRegister8(uint8_t a, uint8_t d) {
writeRegister8inline(a, d);
}
#endif
#ifndef writeRegister16
void Adafruit_ILI9341_8bit_AS::writeRegister16(uint16_t a, uint16_t d) {
writeRegister16inline(a, d);
}
#endif
#ifndef writeRegisterPair
void Adafruit_ILI9341_8bit_AS::writeRegisterPair(uint8_t aH, uint8_t aL, uint16_t d) {
writeRegisterPairInline(aH, aL, d);
}
#endif
void Adafruit_ILI9341_8bit_AS::writeRegister24(uint8_t r, uint32_t d) {
CS_ACTIVE;
CD_COMMAND;
write8(r);
CD_DATA;
delayMicroseconds(10);
write8(d >> 16);
delayMicroseconds(10);
write8(d >> 8);
delayMicroseconds(10);
write8(d);
CS_IDLE;
}
void Adafruit_ILI9341_8bit_AS::writeRegister32(uint8_t r, uint32_t d) {
CS_ACTIVE;
CD_COMMAND;
write8(r);
CD_DATA;
delayMicroseconds(10);
write8(d >> 24);
delayMicroseconds(10);
write8(d >> 16);
delayMicroseconds(10);
write8(d >> 8);
delayMicroseconds(10);
write8(d);
CS_IDLE;
}

View File

@@ -1,105 +0,0 @@
// IMPORTANT: SEE COMMENTS @ LINE 15 REGARDING SHIELD VS BREAKOUT BOARD USAGE.
// Graphics library by ladyada/adafruit with init code from Rossum
// MIT license
#ifndef _ADAFRUIT_ILI9341_8bit_AS_H_
#define _ADAFRUIT_ILI9341_8bit_AS_H_
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "Adafruit_GFX_AS.h"
// **** IF USING THE LCD BREAKOUT BOARD, COMMENT OUT THIS NEXT LINE. ****
// **** IF USING THE LCD SHIELD, LEAVE THE LINE ENABLED: ****
//#define USE_ADAFRUIT_SHIELD_PINOUT 1
class Adafruit_ILI9341_8bit_AS : public Adafruit_GFX_AS {
public:
Adafruit_ILI9341_8bit_AS(uint8_t cs, uint8_t cd, uint8_t wr, uint8_t rd, uint8_t rst);
Adafruit_ILI9341_8bit_AS(void);
void begin(uint16_t id = 0x9325);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color);
void drawFastVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t c);
void fillScreen(uint16_t color);
void reset(void);
void setRegisters8(uint8_t *ptr, uint8_t n);
void setRegisters16(uint16_t *ptr, uint8_t n);
void setRotation(uint8_t x);
// These methods are public in order for BMP examples to work:
void setAddrWindow(int x1, int y1, int x2, int y2);
void pushColors(uint16_t *data, uint8_t len, boolean first);
uint16_t color565(uint8_t r, uint8_t g, uint8_t b),
readPixel(int16_t x, int16_t y),
readID(void);
uint32_t readReg(uint8_t r);
private:
void init(),
// These items may have previously been defined as macros
// in pin_magic.h. If not, function versions are declared:
#ifndef write8
write8(uint8_t value),
#endif
#ifndef setWriteDir
setWriteDir(void),
#endif
#ifndef setReadDir
setReadDir(void),
#endif
#ifndef writeRegister8
writeRegister8(uint8_t a, uint8_t d),
#endif
#ifndef writeRegister16
writeRegister16(uint16_t a, uint16_t d),
#endif
writeRegister24(uint8_t a, uint32_t d),
writeRegister32(uint8_t a, uint32_t d),
#ifndef writeRegisterPair
writeRegisterPair(uint8_t aH, uint8_t aL, uint16_t d),
#endif
setLR(void),
flood(uint16_t color, uint32_t len);
uint8_t driver;
#ifndef read8
uint8_t read8fn(void);
#define read8isFunctionalized
#endif
#ifndef USE_ADAFRUIT_SHIELD_PINOUT
#ifdef __AVR__
volatile uint8_t *csPort , *cdPort , *wrPort , *rdPort;
uint8_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
csPinUnset, cdPinUnset, wrPinUnset, rdPinUnset,
_reset;
#endif
#if defined(__SAM3X8E__)
Pio *csPort , *cdPort , *wrPort , *rdPort;
uint32_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
csPinUnset, cdPinUnset, wrPinUnset, rdPinUnset,
_reset;
#endif
#endif
};
// For compatibility with sketches written for older versions of library.
// Color function name was changed to 'color565' for parity with 2.2" LCD
// library.
#define Color565 color565
#endif

View File

@@ -1,126 +0,0 @@
#ifndef _pin_magic_
#define _pin_magic_
// This header file serves two purposes:
//
// 1) Isolate non-portable MCU port- and pin-specific identifiers and
// operations so the library code itself remains somewhat agnostic
// (PORTs and pin numbers are always referenced through macros).
//
// 2) GCC doesn't always respect the "inline" keyword, so this is a
// ham-fisted manner of forcing the issue to minimize function calls.
// This sometimes makes the library a bit bigger than before, but fast++.
// However, because they're macros, we need to be SUPER CAREFUL about
// parameters -- for example, write8(x) may expand to multiple PORT
// writes that all refer to x, so it needs to be a constant or fixed
// variable and not something like *ptr++ (which, after macro
// expansion, may increment the pointer repeatedly and run off into
// la-la land). Macros also give us fine-grained control over which
// operations are inlined on which boards (balancing speed against
// available program space).
// When using the TFT shield, control and data pins exist in set physical
// locations, but the ports and bitmasks corresponding to each vary among
// boards. A separate set of pin definitions is given for each supported
// board type.
// When using the TFT breakout board, control pins are configurable but
// the data pins are still fixed -- making every data pin configurable
// would be much too slow. The data pin layouts are not the same between
// the shield and breakout configurations -- for the latter, pins were
// chosen to keep the tutorial wiring manageable more than making optimal
// use of ports and bitmasks. So there's a second set of pin definitions
// given for each supported board.
// Shield pin usage:
// Breakout pin usage:
// LCD Data Bit : 7 6 5 4 3 2 1 0
// Uno dig. pin : 7 6 5 4 3 2 9 8
// Uno port/pin : PD7 PD6 PD5 PD4 PD3 PD2 PB1 PB0
// Mega dig. pin: 27 6 5 4 3 2 9 8
// Mega port/pin: PH4 PH3 PE3 PG5 PE5 PE4 PH6 PH5
// Pixel read operations require a minimum 400 nS delay from RD_ACTIVE
// to polling the input pins. At 16 MHz, one machine cycle is 62.5 nS.
// This code burns 7 cycles (437.5 nS) doing nothing; the RJMPs are
// equivalent to two NOPs each, final NOP burns the 7th cycle, and the
// last line is a radioactive mutant emoticon.
#define DELAY7 \
asm volatile( \
"rjmp .+0" "\n\t" \
"rjmp .+0" "\n\t" \
"rjmp .+0" "\n\t" \
"nop" "\n" \
::);
// As part of the inline control, macros reference other macros...if any
// of these are left undefined, an equivalent function version (non-inline)
// is declared later. The Uno has a moderate amount of program space, so
// only write8() is inlined -- that one provides the most performance
// benefit, but unfortunately also generates the most bloat. This is
// why only certain cases are inlined for each board.
// Arduino Mega, ADK, etc.
// Mega port/pin: PH4 PH3 PE3 PG5 PE5 PE4 PH6 PH5
// Because the MEGA port to pin mapping is very messy it is necessary to shift the data bits around a lot.
#define write8inline(d) { \
PORTE = (PORTE & B11001111) | ((d << 2) & B00110000); \
PORTE = (PORTE & B11110111) | ((d >> 2) & B00001000); \
PORTG = (PORTG & B11011111) | ((d << 1) & B00100000); \
PORTH = (PORTH & B11100111) | ((d >> 3) & B00011000); \
PORTH = (PORTH & B10011111) | ((d << 5) & B01100000); \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
DELAY7; \
result = ((PINH & B00011000) << 3) | ((PINE & B00001000) << 2) | ((PING & B00100000) >> 1) |((PINE & B00110000) >> 2) | ((PINH & B01100000) >> 5); \
RD_IDLE; }
// // These set the PORT directions as required before the write and read
// // operations.
#define setWriteDirInline() { DDRE |= B00111000; DDRG |= B00100000; DDRH |= B01111000;}
#define setReadDirInline() { DDRE &= ~B00111000; DDRG &= ~B00100000; DDRH &= ~B01111000;}
// All of the functions are inlined on the Arduino Mega. When using the
// breakout board, the macro versions aren't appreciably larger than the
// function equivalents, and they're super simple and fast. When using
// the shield, the macros become pretty complicated...but this board has
// so much code space, the macros are used anyway. If you need to free
// up program space, some macros can be removed, at a minor cost in speed.
#define write8 write8inline
#define read8 read8inline
#define setWriteDir setWriteDirInline
#define setReadDir setReadDirInline
#define writeRegister8 writeRegister8inline
#define writeRegister16 writeRegister16inline
#define writeRegisterPair writeRegisterPairInline
// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE *rdPort &= rdPinUnset
#define RD_IDLE *rdPort |= rdPinSet
#define WR_ACTIVE *wrPort &= wrPinUnset
#define WR_IDLE *wrPort |= wrPinSet
#define CD_COMMAND *cdPort &= cdPinUnset
#define CD_DATA *cdPort |= cdPinSet
#define CS_ACTIVE *csPort &= csPinUnset
#define CS_IDLE *csPort |= csPinSet
#endif
// Data read and write strobes, ~2 instructions and always inline
#define RD_STROBE { RD_ACTIVE; RD_IDLE; }
#define WR_STROBE { WR_ACTIVE; WR_IDLE; }
// These higher-level operations are usually functionalized,
// except on Mega where's there's gobs and gobs of program space.
// Set value of TFT register: 8-bit address, 8-bit value
#define writeRegister8inline(a, d) { \
CD_COMMAND; write8(a); CD_DATA; write8(d); }
// Set value of TFT register: 16-bit address, 16-bit value
// See notes at top about macro expansion, hence hi & lo temp vars
#define writeRegister16inline(a, d) { \
uint8_t hi, lo; \
hi = (a) >> 8; lo = (a); CD_COMMAND; write8(hi); write8(lo); \
hi = (d) >> 8; lo = (d); CD_DATA ; write8(hi); write8(lo); }
// Set value of 2 TFT registers: Two 8-bit addresses (hi & lo), 16-bit value
#define writeRegisterPairInline(aH, aL, d) { \
uint8_t hi = (d) >> 8, lo = (d); \
CD_COMMAND; write8(aH); CD_DATA; write8(hi); \
CD_COMMAND; write8(aL); CD_DATA; write8(lo); }

View File

@@ -1,117 +0,0 @@
#ifndef _pin_magic_
#define _pin_magic_
// This header file serves two purposes:
//
// 1) Isolate non-portable MCU port- and pin-specific identifiers and
// operations so the library code itself remains somewhat agnostic
// (PORTs and pin numbers are always referenced through macros).
//
// 2) GCC doesn't always respect the "inline" keyword, so this is a
// ham-fisted manner of forcing the issue to minimize function calls.
// This sometimes makes the library a bit bigger than before, but fast++.
// However, because they're macros, we need to be SUPER CAREFUL about
// parameters -- for example, write8(x) may expand to multiple PORT
// writes that all refer to x, so it needs to be a constant or fixed
// variable and not something like *ptr++ (which, after macro
// expansion, may increment the pointer repeatedly and run off into
// la-la land). Macros also give us fine-grained control over which
// operations are inlined on which boards (balancing speed against
// available program space).
// When using the TFT shield, control and data pins exist in set physical
// locations, but the ports and bitmasks corresponding to each vary among
// boards. A separate set of pin definitions is given for each supported
// board type.
// When using the TFT breakout board, control pins are configurable but
// the data pins are still fixed -- making every data pin configurable
// would be much too slow. The data pin layouts are not the same between
// the shield and breakout configurations -- for the latter, pins were
// chosen to keep the tutorial wiring manageable more than making optimal
// use of ports and bitmasks. So there's a second set of pin definitions
// given for each supported board.
// Shield pin usage:
// Breakout pin usage:
// LCD Data Bit : 7 6 5 4 3 2 1 0
// Uno dig. pin : 7 6 5 4 3 2 9 8
// Uno port/pin : PD7 PD6 PD5 PD4 PD3 PD2 PB1 PB0
// Mega dig. pin: 27 6 5 4 3 2 9 8
// Mega port/pin: PH4 PH3 PE3 PG5 PE5 PE4 PH6 PH5
// Pixel read operations require a minimum 400 nS delay from RD_ACTIVE
// to polling the input pins. At 16 MHz, one machine cycle is 62.5 nS.
// This code burns 7 cycles (437.5 nS) doing nothing; the RJMPs are
// equivalent to two NOPs each, final NOP burns the 7th cycle, and the
// last line is a radioactive mutant emoticon.
#define DELAY7 \
asm volatile( \
"rjmp .+0" "\n\t" \
"rjmp .+0" "\n\t" \
"rjmp .+0" "\n\t" \
"nop" "\n" \
::);
// As part of the inline control, macros reference other macros...if any
// of these are left undefined, an equivalent function version (non-inline)
// is declared later. The Uno has a moderate amount of program space, so
// only write8() is inlined -- that one provides the most performance
// benefit, but unfortunately also generates the most bloat. This is
// why only certain cases are inlined for each board.
//Uno w/Breakout board
// Uno dig. pin : 7 6 5 4 3 2 9 8
// Uno port/pin : PD7 PD6 PD5 PD4 PD3 PD2 PB1 PB0
#define write8inline(d) { \
PORTD = (PORTD & B00000011) | ((d) & B11111100); \
PORTB = (PORTB & B11111100) | ((d) & B00000011); \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
DELAY7; \
result = (PIND & B11111100) | (PINB & B00000011); \
RD_IDLE; }
#define setWriteDirInline() { DDRD |= B11111100; DDRB |= B00000011; }
#define setReadDirInline() { DDRD &= ~B11111100; DDRB &= ~B00000011; }
// All of the functions are inlined on the Arduino Mega. When using the
// breakout board, the macro versions aren't appreciably larger than the
// function equivalents, and they're super simple and fast. When using
// the shield, the macros become pretty complicated...but this board has
// so much code space, the macros are used anyway. If you need to free
// up program space, some macros can be removed, at a minor cost in speed.
#define write8 write8inline
#define read8 read8inline
#define setWriteDir setWriteDirInline
#define setReadDir setReadDirInline
#define writeRegister8 writeRegister8inline
#define writeRegister16 writeRegister16inline
#define writeRegisterPair writeRegisterPairInline
// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE *rdPort &= rdPinUnset
#define RD_IDLE *rdPort |= rdPinSet
#define WR_ACTIVE *wrPort &= wrPinUnset
#define WR_IDLE *wrPort |= wrPinSet
#define CD_COMMAND *cdPort &= cdPinUnset
#define CD_DATA *cdPort |= cdPinSet
#define CS_ACTIVE *csPort &= csPinUnset
#define CS_IDLE *csPort |= csPinSet
#endif
// Data read and write strobes, ~2 instructions and always inline
#define RD_STROBE { RD_ACTIVE; RD_IDLE; }
#define WR_STROBE { WR_ACTIVE; WR_IDLE; }
// These higher-level operations are usually functionalized,
// except on Mega where's there's gobs and gobs of program space.
// Set value of TFT register: 8-bit address, 8-bit value
#define writeRegister8inline(a, d) { \
CD_COMMAND; write8(a); CD_DATA; write8(d); }
// Set value of TFT register: 16-bit address, 16-bit value
// See notes at top about macro expansion, hence hi & lo temp vars
#define writeRegister16inline(a, d) { \
uint8_t hi, lo; \
hi = (a) >> 8; lo = (a); CD_COMMAND; write8(hi); write8(lo); \
hi = (d) >> 8; lo = (d); CD_DATA ; write8(hi); write8(lo); }
// Set value of 2 TFT registers: Two 8-bit addresses (hi & lo), 16-bit value
#define writeRegisterPairInline(aH, aL, d) { \
uint8_t hi = (d) >> 8, lo = (d); \
CD_COMMAND; write8(aH); CD_DATA; write8(hi); \
CD_COMMAND; write8(aL); CD_DATA; write8(lo); }

View File

@@ -1,30 +0,0 @@
#define ILI9341_SOFTRESET 0x01
#define ILI9341_SLEEPIN 0x10
#define ILI9341_SLEEPOUT 0x11
#define ILI9341_NORMALDISP 0x13
#define ILI9341_INVERTOFF 0x20
#define ILI9341_INVERTON 0x21
#define ILI9341_GAMMASET 0x26
#define ILI9341_DISPLAYOFF 0x28
#define ILI9341_DISPLAYON 0x29
#define ILI9341_COLADDRSET 0x2A
#define ILI9341_PAGEADDRSET 0x2B
#define ILI9341_MEMORYWRITE 0x2C
#define ILI9341_MEMCONTROL 0x36
#define ILI9341_MADCTL 0x36
#define ILI9341_PIXELFORMAT 0x3A
#define ILI9341_FRAMECONTROL 0xB1
#define ILI9341_DISPLAYFUNC 0xB6
#define ILI9341_ENTRYMODE 0xB7
#define ILI9341_POWERCONTROL1 0xC0
#define ILI9341_POWERCONTROL2 0xC1
#define ILI9341_VCOMCONTROL1 0xC5
#define ILI9341_VCOMCONTROL2 0xC7
#define ILI9341_MADCTL_MY 0x80
#define ILI9341_MADCTL_MX 0x40
#define ILI9341_MADCTL_MV 0x20
#define ILI9341_MADCTL_ML 0x10
#define ILI9341_MADCTL_BGR 0x08
#define ILI9341_MADCTL_MH 0x04
#define ILI9341_MADCTL_RGB 0x00

View File

@@ -1,928 +0,0 @@
/*
* ST7781 TFT LCD driver for PIC32.
*
* Based on code provided by Smoke And Wires
* https://github.com/Smoke-And-Wires/TFT-Shield-Example-Code
*
* Copyright (C) 2015 Serge Vakulenko <serge@vak.ru>
*
* Permission to use, copy, modify, and distribute this software
* and its documentation for any purpose and without fee is hereby
* granted, provided that the above copyright notice appear in all
* copies and that both that the copyright notice and this
* permission notice and warranty disclaimer appear in supporting
* documentation, and that the name of the author not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
*
* The author disclaim all warranties with regard to this
* software, including all implied warranties of merchantability
* and fitness. In no event shall the author be liable for any
* special, indirect or consequential damages or any damages
* whatsoever resulting from loss of use, data or profits, whether
* in an action of contract, negligence or other tortious action,
* arising out of or in connection with the use or performance of
* this software.
*/
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/user.h>
#include <sys/ioctl.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/tty.h>
#include <sys/kconfig.h>
#include <sys/gpanel.h>
/*
* Display size.
*/
//#define WIDTH 240
//#define HEIGHT 320
#define WIDTH 320
#define HEIGHT 240
/*
* Cursor position for text output.
*/
static int _col, _row;
/*
* ID of the LCD controller chip.
*/
static int _chip_id;
/*
* Delay for 100 nanoseconds.
* Needed to match the /WR and /RD timing requirements.
*/
#if CPU_KHZ <= 10000
# define delay100ns() /* empty */
#elif CPU_KHZ <= 20000
# define delay100ns() asm volatile("nop")
#elif CPU_KHZ <= 30000
# define delay100ns() asm volatile("nop; nop")
#elif CPU_KHZ <= 40000
# define delay100ns() asm volatile("nop; nop; nop")
#elif CPU_KHZ <= 50000
# define delay100ns() asm volatile("nop; nop; nop; nop")
#elif CPU_KHZ <= 60000
# define delay100ns() asm volatile("nop; nop; nop; nop; nop")
#elif CPU_KHZ <= 70000
# define delay100ns() asm volatile("nop; nop; nop; nop; nop; nop")
#else
# define delay100ns() asm volatile("nop; nop; nop; nop; nop; nop; nop; nop")
#endif
/*
* Signal mappings:
* /RESET - reset and initialize the chip.
* /CS - chip select when low.
* /RD - read operation enable.
* /WR - write operation enable.
* RS - command or data mode selection.
* D0-D7 - data bus, bidirectional.
*/
#define RST_IDLE() LAT_SET(LCD_RST_PORT) = 1<<LCD_RST_PIN
#define RST_ACTIVE() LAT_CLR(LCD_RST_PORT) = 1<<LCD_RST_PIN
#define CS_IDLE() LAT_SET(LCD_CS_PORT) = 1<<LCD_CS_PIN
#define CS_ACTIVE() LAT_CLR(LCD_CS_PORT) = 1<<LCD_CS_PIN
#define RD_IDLE() LAT_SET(LCD_RD_PORT) = 1<<LCD_RD_PIN
#define RD_ACTIVE() LAT_CLR(LCD_RD_PORT) = 1<<LCD_RD_PIN
#define WR_IDLE() LAT_SET(LCD_WR_PORT) = 1<<LCD_WR_PIN
#define WR_ACTIVE() LAT_CLR(LCD_WR_PORT) = 1<<LCD_WR_PIN
#define WR_STROBE() { WR_ACTIVE(); delay100ns(); WR_IDLE(); }
#define RS_DATA() LAT_SET(LCD_RS_PORT) = 1<<LCD_RS_PIN
#define RS_COMMAND() LAT_CLR(LCD_RS_PORT) = 1<<LCD_RS_PIN
/*
* ST7781 registers.
*/
#define ST7781_Driver_ID_Code_Read 0x00
#define ST7781_Driver_Output_Control 0x01
#define ST7781_LCD_Driving_Wave_Control 0x02
#define ST7781_Entry_Mode 0x03
#define ST7781_Resize_Control 0x04
#define ST7781_Display_Control_1 0x07
#define ST7781_Display_control_2 0x08
#define ST7781_Display_Control_3 0x09
#define ST7781_Display_Control_4 0x0A
#define ST7781_Frame_Marker_Position 0x0D
#define ST7781_Power_Control_1 0x10
#define ST7781_Power_Control_2 0x11
#define ST7781_Power_Control_3 0x12
#define ST7781_Power_Control_4 0x13
#define ST7781_DRAM_Horizontal_Address_Set 0x20
#define ST7781_DRAM_Vertical_Address_Set 0x21
#define ST7781_Write_Data_to_DRAM 0x22
#define ST7781_Read_Data_from_DRAM 0x22
#define ST7781_VCOMH_Control 0x29
#define ST7781_Frame_Rate_and_Color_Control 0x2B
#define ST7781_Gamma_Control_1 0x30
#define ST7781_Gamma_Control_2 0x31
#define ST7781_Gamma_Control_3 0x32
#define ST7781_Gamma_Control_4 0x35
#define ST7781_Gamma_Control_5 0x36
#define ST7781_Gamma_Control_6 0x37
#define ST7781_Gamma_Control_7 0x38
#define ST7781_Gamma_Control_8 0x39
#define ST7781_Gamma_Control_9 0x3C
#define ST7781_Gamma_Control_10 0x3D
#define ST7781_Horizontal_Address_Start_Position 0x50
#define ST7781_Horizontal_Address_End_Position 0x51
#define ST7781_Vertical_Address_Start_Position 0x52
#define ST7781_Vertical_Address_End_Position 0x53
#define ST7781_Gate_Scan_Control_1 0x60
#define ST7781_Gate_Scan_Control_2 0x61
#define ST7781_Partial_Image_1_Display_Position 0x80
#define ST7781_Partial_Image_1_Start_Address 0x81
#define ST7781_Partial_Image_1_End_Address 0x82
#define ST7781_Partial_Image_2_Display_Position 0x83
#define ST7781_Partial_Image_2_Start_Address 0x84
#define ST7781_Partial_Image_2_End_Address 0x85
#define ST7781_Panel_Interface_Control_1 0x90
#define ST7781_Panel_Interface_Control_2 0x92
#define ST7781_EEPROM_ID_Code 0xD2
#define ST7781_EEPROM_Control_Status 0xD9
#define ST7781_EEPROM_Wite_Command 0xDF
#define ST7781_EEPROM_Enable 0xFA
#define ST7781_EEPROM_VCOM_Offset 0xFE
#define ST7781_FAh_FEh_Enable 0xFF
/*
* Set direction of data bus as output.
*/
static void setWriteDir()
{
TRIS_CLR(LCD_D0_PORT) = 1 << LCD_D0_PIN;
TRIS_CLR(LCD_D1_PORT) = 1 << LCD_D1_PIN;
TRIS_CLR(LCD_D2_PORT) = 1 << LCD_D2_PIN;
TRIS_CLR(LCD_D3_PORT) = 1 << LCD_D3_PIN;
TRIS_CLR(LCD_D4_PORT) = 1 << LCD_D4_PIN;
TRIS_CLR(LCD_D5_PORT) = 1 << LCD_D5_PIN;
TRIS_CLR(LCD_D6_PORT) = 1 << LCD_D6_PIN;
TRIS_CLR(LCD_D7_PORT) = 1 << LCD_D7_PIN;
}
/*
* Set direction of data bus as input.
*/
static void setReadDir()
{
TRIS_SET(LCD_D0_PORT) = 1 << LCD_D0_PIN;
TRIS_SET(LCD_D1_PORT) = 1 << LCD_D1_PIN;
TRIS_SET(LCD_D2_PORT) = 1 << LCD_D2_PIN;
TRIS_SET(LCD_D3_PORT) = 1 << LCD_D3_PIN;
TRIS_SET(LCD_D4_PORT) = 1 << LCD_D4_PIN;
TRIS_SET(LCD_D5_PORT) = 1 << LCD_D5_PIN;
TRIS_SET(LCD_D6_PORT) = 1 << LCD_D6_PIN;
TRIS_SET(LCD_D7_PORT) = 1 << LCD_D7_PIN;
}
/*
* Send a byte to the data bus.
*/
static void writeByte(unsigned value)
{
if (value & 1) {
LAT_SET(LCD_D0_PORT) = 1 << LCD_D0_PIN;
} else {
LAT_CLR(LCD_D0_PORT) = 1 << LCD_D0_PIN;
}
if (value & 2) {
LAT_SET(LCD_D1_PORT) = 1 << LCD_D1_PIN;
} else {
LAT_CLR(LCD_D1_PORT) = 1 << LCD_D1_PIN;
}
if (value & 4) {
LAT_SET(LCD_D2_PORT) = 1 << LCD_D2_PIN;
} else {
LAT_CLR(LCD_D2_PORT) = 1 << LCD_D2_PIN;
}
if (value & 8) {
LAT_SET(LCD_D3_PORT) = 1 << LCD_D3_PIN;
} else {
LAT_CLR(LCD_D3_PORT) = 1 << LCD_D3_PIN;
}
if (value & 0x10) {
LAT_SET(LCD_D4_PORT) = 1 << LCD_D4_PIN;
} else {
LAT_CLR(LCD_D4_PORT) = 1 << LCD_D4_PIN;
}
if (value & 0x20) {
LAT_SET(LCD_D5_PORT) = 1 << LCD_D5_PIN;
} else {
LAT_CLR(LCD_D5_PORT) = 1 << LCD_D5_PIN;
}
if (value & 0x40) {
LAT_SET(LCD_D6_PORT) = 1 << LCD_D6_PIN;
} else {
LAT_CLR(LCD_D6_PORT) = 1 << LCD_D6_PIN;
}
if (value & 0x80) {
LAT_SET(LCD_D7_PORT) = 1 << LCD_D7_PIN;
} else {
LAT_CLR(LCD_D7_PORT) = 1 << LCD_D7_PIN;
}
WR_STROBE();
}
static unsigned readByte()
{
unsigned value = 0;
RD_ACTIVE();
delay100ns();
if (PORT_VAL(LCD_D0_PORT) & (1 << LCD_D0_PIN)) value |= 1;
if (PORT_VAL(LCD_D1_PORT) & (1 << LCD_D1_PIN)) value |= 2;
if (PORT_VAL(LCD_D2_PORT) & (1 << LCD_D2_PIN)) value |= 4;
if (PORT_VAL(LCD_D3_PORT) & (1 << LCD_D3_PIN)) value |= 8;
if (PORT_VAL(LCD_D4_PORT) & (1 << LCD_D4_PIN)) value |= 0x10;
if (PORT_VAL(LCD_D5_PORT) & (1 << LCD_D5_PIN)) value |= 0x20;
if (PORT_VAL(LCD_D6_PORT) & (1 << LCD_D6_PIN)) value |= 0x40;
if (PORT_VAL(LCD_D7_PORT) & (1 << LCD_D7_PIN)) value |= 0x80;
RD_IDLE();
return value;
}
/*
* Write a 16-bit value to the ST7781 register.
*/
static void writeReg(unsigned reg, unsigned value)
{
RS_COMMAND();
writeByte(reg >> 8);
writeByte(reg);
RS_DATA();
writeByte(value >> 8);
writeByte(value);
}
/*
* Read device ID code.
*/
static unsigned readDeviceId()
{
unsigned value;
CS_ACTIVE();
RS_COMMAND();
writeByte(ST7781_Driver_ID_Code_Read);
delay100ns();
WR_STROBE(); // Repeat prior byte
setReadDir(); // Switch data bus as input
RS_DATA();
value = readByte() << 8;
value |= readByte();
setWriteDir(); // Restore data bus as output
CS_IDLE();
return value;
}
/*
* Detect the type of the LCD controller, and initialize it.
* Return -1 in case of unknown chip.
*/
static int initDisplay()
{
/*
* Set all control bits to high (idle).
* Signals are active low.
*/
CS_IDLE();
WR_IDLE();
RD_IDLE();
RST_IDLE();
/* Enable outputs. */
TRIS_CLR(LCD_CS_PORT) = 1 << LCD_CS_PIN;
TRIS_CLR(LCD_RS_PORT) = 1 << LCD_RS_PIN;
TRIS_CLR(LCD_WR_PORT) = 1 << LCD_WR_PIN;
TRIS_CLR(LCD_RD_PORT) = 1 << LCD_RD_PIN;
TRIS_CLR(LCD_RST_PORT) = 1 << LCD_RST_PIN;
setWriteDir();
/* Reset the chip. */
RST_ACTIVE();
udelay(1000);
RST_IDLE();
udelay(1000);
/* Read the the chip ID register. */
_chip_id = readDeviceId();
switch (_chip_id) {
case 0x7783:
printf("swtft0: <Sitronix ST7781>\n");
break;
default:
/* Disable outputs. */
setReadDir();
TRIS_SET(LCD_CS_PORT) = 1 << LCD_CS_PIN;
TRIS_SET(LCD_RS_PORT) = 1 << LCD_RS_PIN;
TRIS_SET(LCD_WR_PORT) = 1 << LCD_WR_PIN;
TRIS_SET(LCD_RD_PORT) = 1 << LCD_RD_PIN;
TRIS_SET(LCD_RST_PORT) = 1 << LCD_RST_PIN;
printf("swtft0: Unknown chip ID = 0x%x\n", _chip_id);
return -1;
}
/* Initialization of LCD controller. */
CS_ACTIVE();
writeReg(ST7781_Driver_Output_Control, 0x0100);
writeReg(ST7781_LCD_Driving_Wave_Control, 0x0700);
//writeReg(ST7781_Entry_Mode, 0x1030);
writeReg(ST7781_Entry_Mode, 0x1028);
writeReg(ST7781_Display_control_2, 0x0302);
writeReg(ST7781_Display_Control_3, 0x0000);
writeReg(ST7781_Display_Control_4, 0x0008);
/* Power control registers. */
writeReg(ST7781_Power_Control_1, 0x0790);
writeReg(ST7781_Power_Control_2, 0x0005);
writeReg(ST7781_Power_Control_3, 0x0000);
writeReg(ST7781_Power_Control_4, 0x0000);
/* Power supply startup 1 settings. */
writeReg(ST7781_Power_Control_1, 0x12B0);
writeReg(ST7781_Power_Control_2, 0x0007);
/* Power supply startup 2 settings. */
writeReg(ST7781_Power_Control_3, 0x008C);
writeReg(ST7781_Power_Control_4, 0x1700);
writeReg(ST7781_VCOMH_Control, 0x0022);
/* Gamma cluster settings. */
writeReg(ST7781_Gamma_Control_1, 0x0000);
writeReg(ST7781_Gamma_Control_2, 0x0505);
writeReg(ST7781_Gamma_Control_3, 0x0205);
writeReg(ST7781_Gamma_Control_4, 0x0206);
writeReg(ST7781_Gamma_Control_5, 0x0408);
writeReg(ST7781_Gamma_Control_6, 0x0000);
writeReg(ST7781_Gamma_Control_7, 0x0504);
writeReg(ST7781_Gamma_Control_8, 0x0206);
writeReg(ST7781_Gamma_Control_9, 0x0206);
writeReg(ST7781_Gamma_Control_10, 0x0408);
/* Frame rate settings. */
writeReg(ST7781_Gate_Scan_Control_1, 0xA700);
writeReg(ST7781_Gate_Scan_Control_2, 0x0001);
writeReg(ST7781_Panel_Interface_Control_1, 0x0033); // RTNI setting
/* Display on. */
writeReg(ST7781_Display_Control_1, 0x0133);
return 0;
}
static void setAddrWindow(int x0, int y0, int x1, int y1)
{
if (WIDTH > HEIGHT) {
/* Landscape mode. */
int t;
t = x0;
x0 = HEIGHT-1 - y1;
y1 = x1;
x1 = HEIGHT-1 - y0;
y0 = t;
}
/* Set address window. */
CS_ACTIVE();
writeReg(ST7781_Horizontal_Address_Start_Position, x0);
writeReg(ST7781_Horizontal_Address_End_Position, x1);
writeReg(ST7781_Vertical_Address_Start_Position, y0);
writeReg(ST7781_Vertical_Address_End_Position, y1);
/* Set address counter to top left. */
//writeReg(ST7781_DRAM_Horizontal_Address_Set, (WIDTH > HEIGHT) ? x1 : x0);
writeReg(ST7781_DRAM_Horizontal_Address_Set, x0);
writeReg(ST7781_DRAM_Vertical_Address_Set, y0);
CS_IDLE();
}
/*
* Draw a pixel.
*/
static void setPixel(int x, int y, int color)
{
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
return;
CS_ACTIVE();
if (WIDTH > HEIGHT) {
/* Landscape mode. */
writeReg(ST7781_DRAM_Horizontal_Address_Set, HEIGHT-1 - y);
writeReg(ST7781_DRAM_Vertical_Address_Set, x);
} else {
/* Portrait mode. */
writeReg(ST7781_DRAM_Horizontal_Address_Set, x);
writeReg(ST7781_DRAM_Vertical_Address_Set, y);
}
writeReg(ST7781_Write_Data_to_DRAM, color);
CS_IDLE();
}
/*
* Fast block fill operation.
* Requires setAddrWindow() has previously been called to set
* the fill bounds.
* 'npixels' is inclusive, MUST be >= 1.
*/
static void flood(int color, int npixels)
{
unsigned blocks, i;
unsigned hi = color >> 8,
lo = color;
CS_ACTIVE();
RS_COMMAND();
writeByte(0x00); /* High address byte */
writeByte(ST7781_Write_Data_to_DRAM);
/* Write first pixel normally, decrement counter by 1. */
RS_DATA();
writeByte(hi);
writeByte(lo);
npixels--;
/* 64 pixels/block. */
blocks = npixels >> 6;
if (hi == lo) {
/* High and low bytes are identical. Leave prior data
* on the port(s) and just toggle the write strobe. */
while (blocks--) {
/* 64 pixels/block / 4 pixels/pass. */
for (i = 16; i > 0; i--) {
/* 2 bytes/pixel x 4 pixels. */
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
}
}
/* Fill any remaining pixels (1 to 64). */
for (i = npixels & 63; i > 0; i--) {
delay100ns(); WR_STROBE();
delay100ns(); WR_STROBE();
}
} else {
while (blocks--) {
/* 64 pixels/block / 4 pixels/pass. */
for (i = 16; i > 0; i--) {
writeByte(hi); writeByte(lo); writeByte(hi); writeByte(lo);
writeByte(hi); writeByte(lo); writeByte(hi); writeByte(lo);
}
}
for (i = npixels & 63; i > 0; i--) {
writeByte(hi);
writeByte(lo);
}
}
CS_IDLE();
}
/*
* Fill a rectangle with specified color.
*/
static void fillRectangle(int x0, int y0, int x1, int y1, int color)
{
if (x0 < 0) x0 = 0;
if (y0 < 0) x0 = 0;
if (x1 < 0) x1 = 0;
if (y1 < 0) x1 = 0;
if (x0 >= WIDTH) x0 = WIDTH-1;
if (x1 >= WIDTH) x1 = WIDTH-1;
if (y0 >= HEIGHT) y0 = HEIGHT-1;
if (y1 >= HEIGHT) y1 = HEIGHT-1;
if (x1 < x0) {
int t = x0;
x0 = x1;
x1 = t;
}
if (y1 < y0) {
int t = y0;
y0 = y1;
y1 = t;
}
setAddrWindow(x0, y0, x1, y1);
flood(color, (x1 - x0 + 1) * (y1 - y0 + 1));
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
}
/*
* Fill a rectangle with user data.
*/
static void drawImage(int x, int y, int width, int height,
const unsigned short *data)
{
unsigned cnt = width * height;
int color;
setAddrWindow(x, y, x + width - 1, y + height - 1);
CS_ACTIVE();
RS_COMMAND();
writeByte(0x00); /* High address byte */
writeByte(ST7781_Write_Data_to_DRAM);
RS_DATA();
while (cnt--) {
color = *data++;
writeByte(color >> 8);
writeByte(color);
}
CS_IDLE();
if (WIDTH > HEIGHT)
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
}
/*
* Draw a line.
*/
static void drawLine(int x0, int y0, int x1, int y1, int color)
{
int dx, dy, stepx, stepy, fraction;
if (x0 == x1 || y0 == y1) {
fillRectangle(x0, y0, x1, y1, color);
return;
}
/* Use Bresenham's line algorithm. */
dy = y1 - y0;
if (dy < 0) {
dy = -dy;
stepy = -1;
} else {
stepy = 1;
}
dx = x1 - x0;
if (dx < 0) {
dx = -dx;
stepx = -1;
} else {
stepx = 1;
}
dy <<= 1; /* dy is now 2*dy */
dx <<= 1; /* dx is now 2*dx */
setPixel(x0, y0, color);
if (dx > dy) {
fraction = dy - (dx >> 1); /* same as 2*dy - dx */
while (x0 != x1) {
if (fraction >= 0) {
y0 += stepy;
fraction -= dx; /* same as fraction -= 2*dx */
}
x0 += stepx;
fraction += dy; /* same as fraction -= 2*dy */
setPixel(x0, y0, color);
}
} else {
fraction = dx - (dy >> 1);
while (y0 != y1) {
if (fraction >= 0) {
x0 += stepx;
fraction -= dy;
}
y0 += stepy;
fraction += dx;
setPixel(x0, y0, color);
}
}
}
/*
* Draw a rectangular frame.
*/
static void drawFrame(int x0, int y0, int x1, int y1, int color)
{
fillRectangle(x0, y0, x1, y0, color);
fillRectangle(x0, y1, x1, y1, color);
fillRectangle(x0, y0, x0, y1, color);
fillRectangle(x1, y0, x1, y1, color);
}
/*
* Draw a circle.
*/
static void drawCircle(int x0, int y0, int radius, int color)
{
int f = 1 - radius;
int ddF_x = 0;
int ddF_y = -2 * radius;
int x = 0;
int y = radius;
setPixel(x0, y0 + radius, color);
setPixel(x0, y0 - radius, color);
setPixel(x0 + radius, y0, color);
setPixel(x0 - radius, y0, color);
while (x < y) {
if (f >= 0) {
y--;
ddF_y += 2;
f += ddF_y;
}
x++;
ddF_x += 2;
f += ddF_x + 1;
setPixel(x0 + x, y0 + y, color);
setPixel(x0 - x, y0 + y, color);
setPixel(x0 + x, y0 - y, color);
setPixel(x0 - x, y0 - y, color);
setPixel(x0 + y, y0 + x, color);
setPixel(x0 - y, y0 + x, color);
setPixel(x0 + y, y0 - x, color);
setPixel(x0 - y, y0 - x, color);
}
}
/*
* Start a new line: increase row.
*/
static void newLine(const struct gpanel_font_t *font)
{
_col = 0;
_row += font->height;
if (_row > HEIGHT - font->height)
_row = 0;
}
/*
* Draw a glyph of one symbol.
*/
static void drawGlyph(const struct gpanel_font_t *font,
int color, int background, int width, const unsigned short *bits)
{
int h, w, c;
unsigned bitmask = 0;
if (background >= 0) {
/*
* Clear background.
*/
setAddrWindow(_col, _row, _col + width - 1, _row + font->height - 1);
CS_ACTIVE();
RS_COMMAND();
writeByte(0x00); /* High address byte */
writeByte(ST7781_Write_Data_to_DRAM);
RS_DATA();
/* Loop on each glyph row. */
for (h=0; h<font->height; h++) {
/* Loop on every pixel in the row (left to right). */
for (w=0; w<width; w++) {
if ((w & 15) == 0)
bitmask = *bits++;
else
bitmask <<= 1;
c = (bitmask & 0x8000) ? color : background;
writeByte(c >> 8);
writeByte(c);
}
}
CS_IDLE();
} else {
/*
* Transparent background.
*/
/* Loop on each glyph row. */
for (h=0; h<font->height; h++) {
/* Loop on every pixel in the row (left to right). */
for (w=0; w<width; w++) {
if ((w & 15) == 0)
bitmask = *bits++;
else
bitmask <<= 1;
if (bitmask & 0x8000)
setPixel(_col + w, _row + h, color);
}
}
}
}
/*
* Draw a character from a specified font.
*/
static void drawChar(const struct gpanel_font_t *font,
int color, int background, int sym)
{
unsigned cindex, width;
const unsigned short *bits;
switch (sym) {
case '\n': /* goto next line */
newLine(font);
return;
case '\r': /* carriage return - go to begin of line */
_col = 0;
return;
case '\t': /* tab replaced by space */
sym = ' ';
break;
}
if (sym < font->firstchar || sym >= font->firstchar + font->size)
sym = font->defaultchar;
cindex = sym - font->firstchar;
/* Get font bitmap depending on fixed pitch or not. */
if (font->width) {
/* Proportional font. */
width = font->width[cindex];
} else {
/* Fixed width font. */
width = font->maxwidth;
}
if (font->offset) {
bits = font->bits + font->offset[cindex];
} else {
bits = font->bits + cindex * font->height;
}
/* Draw a character. */
if (_col < WIDTH)
drawGlyph(font, color, background, width, bits);
_col += width;
}
/*
* Draw a string of characters.
* TODO: Decode UTF-8.
*/
static void drawText(const struct gpanel_font_t *font,
int color, int background, int x, int y, const char *text)
{
int sym;
_col = x;
_row = y;
for (;;) {
sym = *text++;
if (! sym)
break;
drawChar(font, color, background, sym);
}
if (WIDTH > HEIGHT)
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
}
int gpanel_open(dev_t dev, int flag, int mode)
{
if (minor(dev) != 0)
return ENODEV;
return 0;
}
int gpanel_close(dev_t dev, int flag, int mode)
{
return 0;
}
int gpanel_read(dev_t dev, struct uio *uio, int flag)
{
return ENODEV;
}
int gpanel_write(dev_t dev, struct uio *uio, int flag)
{
return ENODEV;
}
/*
* TODO: check whether user pointers are valid.
*/
int gpanel_ioctl(dev_t dev, register u_int cmd, caddr_t addr, int flag)
{
switch (cmd) {
/*
* Clear the whole screen with a given color.
*/
case GPANEL_CLEAR: {
struct gpanel_clear_t *param = (struct gpanel_clear_t*) addr;
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
flood(param->color, WIDTH * HEIGHT);
if (WIDTH > HEIGHT)
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
param->xsize = WIDTH;
param->ysize = HEIGHT;
break;
}
/*
* Draw a single pixel.
*/
case GPANEL_PIXEL: {
struct gpanel_pixel_t *param = (struct gpanel_pixel_t*) addr;
setPixel(param->x, param->y, param->color);
break;
}
/*
* Draw a line.
*/
case GPANEL_LINE: {
struct gpanel_line_t *param = (struct gpanel_line_t*) addr;
drawLine(param->x0, param->y0, param->x1, param->y1, param->color);
break;
}
/*
* Draw a rectangle frame.
*/
case GPANEL_RECT: {
struct gpanel_rect_t *param = (struct gpanel_rect_t*) addr;
drawFrame(param->x0, param->y0, param->x1, param->y1, param->color);
break;
}
/*
* Fill a rectangle with color.
*/
case GPANEL_FILL: {
struct gpanel_rect_t *param = (struct gpanel_rect_t*) addr;
fillRectangle(param->x0, param->y0, param->x1, param->y1, param->color);
break;
}
/*
* Draw a circle.
*/
case GPANEL_CIRCLE: {
struct gpanel_circle_t *param = (struct gpanel_circle_t*) addr;
drawCircle(param->x, param->y, param->radius, param->color);
break;
}
/*
* Fill a rectangular area with the user-supplied data.
*/
case GPANEL_IMAGE: {
struct gpanel_image_t *param = (struct gpanel_image_t*) addr;
drawImage(param->x, param->y, param->width, param->height,
param->image);
break;
}
/*
* Draw a character.
*/
case GPANEL_CHAR: {
struct gpanel_char_t *param = (struct gpanel_char_t*) addr;
_col = param->x;
_row = param->y;
drawChar(param->font, param->color, param->background, param->sym);
if (WIDTH > HEIGHT)
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
break;
}
/*
* Draw a string of characters.
*/
case GPANEL_TEXT: {
struct gpanel_text_t *param = (struct gpanel_text_t*) addr;
drawText(param->font, param->color, param->background,
param->x, param->y, param->text);
break;
}
}
return 0;
}
/*
* Test to see if device is present.
* Return true if found and initialized ok.
*/
static int
swtftprobe(config)
struct conf_device *config;
{
if (initDisplay() < 0)
return 0;
printf("swtft0: display %ux%u\n", WIDTH, HEIGHT);
setAddrWindow(0, 0, WIDTH-1, HEIGHT-1);
return 1;
}
struct driver swtftdriver = {
"swtft", swtftprobe,
};