Merge gpanel branch.
This commit is contained in:
@@ -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;
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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); }
|
|
||||||
|
|
||||||
@@ -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); }
|
|
||||||
|
|
||||||
@@ -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
|
|
||||||
@@ -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,
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user