mirror of
https://github.com/adafruit/TFTLCD-Library.git
synced 2026-09-11 17:13:09 +00:00
readPixel() working, more robust readID()
This commit is contained in:
+49
-33
@@ -301,7 +301,6 @@ void Adafruit_TFTLCD::begin(uint16_t id) {
|
||||
void Adafruit_TFTLCD::reset(void) {
|
||||
|
||||
CS_IDLE;
|
||||
CD_DATA;
|
||||
WR_IDLE;
|
||||
RD_IDLE;
|
||||
|
||||
@@ -317,12 +316,12 @@ void Adafruit_TFTLCD::reset(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Data transfer sync
|
||||
CS_ACTIVE;
|
||||
CD_DATA;
|
||||
CD_COMMAND;
|
||||
write8(0x00);
|
||||
for(uint8_t i=0; i<7; i++) WR_STROBE;
|
||||
for(uint8_t i=0; i<3; i++) WR_STROBE; // Three extra 0x00s
|
||||
CS_IDLE;
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// Sets the LCD address window (and address counter, on 932X).
|
||||
@@ -679,19 +678,22 @@ void Adafruit_TFTLCD::setRotation(uint8_t x) {
|
||||
}
|
||||
}
|
||||
|
||||
#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_TFTLCD::readPixel(int16_t x, int16_t y) {
|
||||
|
||||
uint16_t c;
|
||||
|
||||
if((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return 0;
|
||||
|
||||
CS_ACTIVE;
|
||||
if(driver == ID_932X) {
|
||||
|
||||
uint8_t hi, lo;
|
||||
int16_t t;
|
||||
switch(rotation) {
|
||||
case 1:
|
||||
@@ -711,45 +713,59 @@ uint16_t Adafruit_TFTLCD::readPixel(int16_t x, int16_t y) {
|
||||
}
|
||||
writeRegister16(0x0020, x);
|
||||
writeRegister16(0x0021, y);
|
||||
CD_COMMAND; write8(0x00); write8(0x22); // Read data from GRAM
|
||||
// Inexplicable thing: sometimes pixel read has high/low bytes
|
||||
// reversed. A second read fixes this. Unsure of reason. Have
|
||||
// tried adjusting timing in read8() etc. to no avail.
|
||||
for(uint8_t pass=0; pass<2; pass++) {
|
||||
CD_COMMAND; write8(0x00); write8(0x22); // Read data from GRAM
|
||||
CD_DATA;
|
||||
setReadDir(); // Set up LCD data port(s) for READ operations
|
||||
read8(hi); // First 2 bytes back are a dummy read
|
||||
read8(hi);
|
||||
read8(hi); // Bytes 3, 4 are actual pixel value
|
||||
read8(lo);
|
||||
setWriteDir(); // Restore LCD data port(s) to WRITE configuration
|
||||
}
|
||||
CS_IDLE;
|
||||
return ((uint16_t)hi << 8) | lo;
|
||||
|
||||
} else if(driver == ID_7575) {
|
||||
|
||||
uint8_t r, g, b;
|
||||
writeRegisterPair(HX8347G_COLADDRSTART_HI, HX8347G_COLADDRSTART_LO, x);
|
||||
writeRegisterPair(HX8347G_ROWADDRSTART_HI, HX8347G_ROWADDRSTART_LO, y);
|
||||
CD_COMMAND; write8(0x22); // Read data from GRAM
|
||||
}
|
||||
|
||||
setReadDir(); // Set up LCD data port(s) for READ operations
|
||||
CD_DATA;
|
||||
c = read8(); // Do not merge or otherwise simplify
|
||||
c <<= 8; // these lines. It's an unfortunate
|
||||
delayMicroseconds(1); // artifact of the macro substitution
|
||||
c |= read8(); // shenanigans that are going on.
|
||||
setWriteDir(); // Restore LCD data port(s) to WRITE configuration
|
||||
CS_IDLE;
|
||||
|
||||
return c;
|
||||
setReadDir(); // Set up LCD data port(s) for READ operations
|
||||
CD_DATA;
|
||||
read8(r); // First byte back is a dummy read
|
||||
read8(r);
|
||||
read8(g);
|
||||
read8(b);
|
||||
setWriteDir(); // Restore LCD data port(s) to WRITE configuration
|
||||
CS_IDLE;
|
||||
return (((uint16_t)r & B11111000) << 8) |
|
||||
(((uint16_t)g & B11111100) << 3) |
|
||||
( b >> 3);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
// Ditto with the read/write port directions, as above.
|
||||
uint16_t Adafruit_TFTLCD::readID(void) {
|
||||
|
||||
uint16_t id;
|
||||
uint8_t hi, lo;
|
||||
|
||||
CS_ACTIVE;
|
||||
CD_COMMAND;
|
||||
write8(0x00);
|
||||
write8(0x00);
|
||||
WR_STROBE; // Repeat prior byte (0x00)
|
||||
setReadDir(); // Set up LCD data port(s) for READ operations
|
||||
CD_DATA;
|
||||
delayMicroseconds(10);
|
||||
id = read8(); // Do not merge or otherwise simplify
|
||||
id <<= 8; // these lines. It's an unfortunate
|
||||
delayMicroseconds(10); // artifact of the macro substitution
|
||||
id |= read8(); // shenanigans that are going on.
|
||||
CS_IDLE;
|
||||
read8(hi);
|
||||
read8(lo);
|
||||
setWriteDir(); // Restore LCD data port(s) to WRITE configuration
|
||||
CS_IDLE;
|
||||
|
||||
return id;
|
||||
return (hi << 8) | lo;
|
||||
}
|
||||
|
||||
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
|
||||
@@ -766,11 +782,11 @@ void Adafruit_TFTLCD::write8(uint8_t value) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef read8
|
||||
uint8_t Adafruit_TFTLCD::read8(void) {
|
||||
// Do not merge or simplify -- macro shenanigans going on!
|
||||
uint8_t d = read8inline();
|
||||
return d;
|
||||
#ifdef read8isFunctionalized
|
||||
uint8_t Adafruit_TFTLCD::read8fn(void) {
|
||||
uint8_t result;
|
||||
read8inline(result);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+4
-4
@@ -38,10 +38,6 @@ class Adafruit_TFTLCD : public Adafruit_GFX {
|
||||
setAddrWindow(int x1, int y1, int x2, int y2),
|
||||
pushColors(uint16_t *data, uint8_t len, boolean first);
|
||||
|
||||
#ifndef read8
|
||||
uint8_t read8(void); // See notes below re: macros
|
||||
#endif
|
||||
|
||||
uint16_t color565(uint8_t r, uint8_t g, uint8_t b),
|
||||
readPixel(int16_t x, int16_t y),
|
||||
readID(void);
|
||||
@@ -72,6 +68,10 @@ class Adafruit_TFTLCD : public Adafruit_GFX {
|
||||
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
|
||||
volatile uint8_t *csPort , *cdPort , *wrPort , *rdPort;
|
||||
uint8_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
|
||||
|
||||
+104
-74
@@ -15,7 +15,7 @@
|
||||
// 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 fune-grained control over which
|
||||
// la-la land). Macros also give us fine-grained control over which
|
||||
// operations are inlined on which boards (balancing speed against
|
||||
// available program space).
|
||||
|
||||
@@ -46,6 +46,19 @@
|
||||
// Leo dig. pin : 7 6 5 4 3 2 9 8
|
||||
// Leo port/pin : PE6 PD7 PC6 PD4 PD0 PD1 PB5 PB4
|
||||
|
||||
// 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" \
|
||||
::);
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined(__AVR_ATmega8__)
|
||||
|
||||
// Arduino Uno, Duemilanove, etc.
|
||||
@@ -66,13 +79,19 @@
|
||||
// These are macros for I/O operations...
|
||||
|
||||
// Write 8-bit value to LCD data lines
|
||||
#define write8inline(d) { \
|
||||
PORTD = (PORTD & B00101111) | ((d) & B11010000); \
|
||||
PORTB = (PORTB & B11010000) | ((d) & B00101111); \
|
||||
WR_STROBE; } // STROBEs are defined later
|
||||
#define write8inline(d) { \
|
||||
PORTD = (PORTD & B00101111) | ((d) & B11010000); \
|
||||
PORTB = (PORTB & B11010000) | ((d) & B00101111); \
|
||||
WR_STROBE; } // STROBEs are defined later
|
||||
|
||||
// Read 8-bit value from LCD data lines
|
||||
#define read8inline() (RD_STROBE, (PIND & B11010000) | (PINB & B00101111))
|
||||
// Read 8-bit value from LCD data lines. The signle argument
|
||||
// is a destination variable; this isn't a function and doesn't
|
||||
// return a value in the conventional sense.
|
||||
#define read8inline(result) { \
|
||||
RD_ACTIVE; \
|
||||
DELAY7; \
|
||||
result = (PIND & B11010000) | (PINB & B00101111); \
|
||||
RD_IDLE; }
|
||||
|
||||
// These set the PORT directions as required before the write and read
|
||||
// operations. Because write operations are much more common than reads,
|
||||
@@ -85,13 +104,17 @@
|
||||
|
||||
#else // Uno w/Breakout board
|
||||
|
||||
#define write8inline(d) { \
|
||||
PORTD = (PORTD & B00000011) | ((d) & B11111100); \
|
||||
PORTB = (PORTB & B11111100) | ((d) & B00000011); \
|
||||
WR_STROBE; }
|
||||
#define read8inline() (RD_STROBE, (PIND& B11111100)|(PINB& B00000011))
|
||||
#define setWriteDirInline() { DDRD|= B11111100; DDRB|= B00000011; }
|
||||
#define setReadDirInline() { DDRD&=~B11111100; DDRB&=~B00000011; }
|
||||
#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; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -99,7 +122,8 @@
|
||||
// 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 also generates the most bloat.
|
||||
// benefit, but unfortunately also generates the most bloat. This is
|
||||
// why only certain cases are inlined for each board.
|
||||
#define write8 write8inline
|
||||
|
||||
#elif defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)
|
||||
@@ -117,29 +141,32 @@
|
||||
#define CD_MASK B00000100
|
||||
#define CS_MASK B00001000
|
||||
|
||||
#define write8inline(d) { \
|
||||
PORTH = (PORTH & B10000111)|(((d) & B11000000)>>3)|(((d) & B00000011)<<5); \
|
||||
PORTB = (PORTB & B01001111)|(((d) & B00101100)<<2); \
|
||||
PORTG = (PORTG & B11011111)|(((d) & B00010000)<<1); \
|
||||
WR_STROBE; }
|
||||
#define read8inline() (RD_STROBE, \
|
||||
((PINH & B00011000) << 3) | ((PINB & B10110000) >> 2) | \
|
||||
((PING & B00100000) >> 1) | ((PINH & B01100000) >> 5))
|
||||
#define setWriteDirInline() { \
|
||||
DDRH |= B01111000; DDRB |= B10110000; DDRG |= B00100000; }
|
||||
#define setReadDirInline() { \
|
||||
DDRH &= ~B01111000; DDRB &= ~B10110000; DDRG &= ~B00100000; }
|
||||
|
||||
// Strobe is wonky on Mega w/shield. Haven't worked out the underlying
|
||||
// reason, but an interim kludge is just to use inverted levels. ???
|
||||
#define RD_STROBE RD_IDLE, RD_ACTIVE
|
||||
#define write8inline(d) { \
|
||||
PORTH = (PORTH&B10000111)|(((d)&B11000000)>>3)|(((d)&B00000011)<<5); \
|
||||
PORTB = (PORTB&B01001111)|(((d)&B00101100)<<2); \
|
||||
PORTG = (PORTG&B11011111)|(((d)&B00010000)<<1); \
|
||||
WR_STROBE; }
|
||||
#define read8inline(result) { \
|
||||
RD_ACTIVE; \
|
||||
DELAY7; \
|
||||
result = ((PINH & B00011000) << 3) | ((PINB & B10110000) >> 2) | \
|
||||
((PING & B00100000) >> 1) | ((PINH & B01100000) >> 5); \
|
||||
RD_IDLE; }
|
||||
#define setWriteDirInline() { \
|
||||
DDRH |= B01111000; DDRB |= B10110000; DDRG |= B00100000; }
|
||||
#define setReadDirInline() { \
|
||||
DDRH &= ~B01111000; DDRB &= ~B10110000; DDRG &= ~B00100000; }
|
||||
|
||||
#else // Mega w/Breakout board
|
||||
|
||||
#define write8inline(d) { PORTA = (d); WR_STROBE; }
|
||||
#define read8inline() (RD_STROBE, PINA)
|
||||
#define setWriteDirInline() DDRA = 0xff
|
||||
#define setReadDirInline() DDRA = 0
|
||||
#define write8inline(d) { PORTA = (d); WR_STROBE; }
|
||||
#define read8inline(result) { \
|
||||
RD_ACTIVE; \
|
||||
DELAY7; \
|
||||
result = PINA; \
|
||||
RD_IDLE; }
|
||||
#define setWriteDirInline() DDRA = 0xff
|
||||
#define setReadDirInline() DDRA = 0
|
||||
|
||||
#endif
|
||||
|
||||
@@ -172,44 +199,50 @@
|
||||
#define CD_MASK B00100000
|
||||
#define CS_MASK B00010000
|
||||
|
||||
#define write8inline(d) { \
|
||||
PORTE = (PORTE & B10111111) | (((d) & B10000000)>>1); \
|
||||
PORTD = (PORTD & B01101111) | (((d) & B01000000)<<1) | ((d) & B00010000); \
|
||||
PORTC = (PORTC & B01111111) | (((d) & B00100000)<<2); \
|
||||
PORTB = (PORTB & B00001111) | (((d) & B00001111)<<4); \
|
||||
WR_STROBE; }
|
||||
#define read8inline() (RD_STROBE, \
|
||||
(((PINE & B01000000) << 1) | ((PIND & B10000000) >> 1) | \
|
||||
((PINC & B10000000) >> 2) | ((PINB & B11110000) >> 4) | \
|
||||
(PIND & B00010000)))
|
||||
#define setWriteDirInline() { \
|
||||
DDRE |= B01000000; DDRD |= B10010000; \
|
||||
DDRC |= B10000000; DDRB |= B11110000; }
|
||||
#define setReadDirInline() { \
|
||||
DDRE &= ~B01000000; DDRD &= ~B10010000; \
|
||||
DDRC &= ~B10000000; DDRB &= ~B11110000; }
|
||||
#define write8inline(d) { \
|
||||
PORTE = (PORTE & B10111111) | (((d) & B10000000)>>1); \
|
||||
PORTD = (PORTD & B01101111) | (((d) & B01000000)<<1) | ((d) & B00010000); \
|
||||
PORTC = (PORTC & B01111111) | (((d) & B00100000)<<2); \
|
||||
PORTB = (PORTB & B00001111) | (((d) & B00001111)<<4); \
|
||||
WR_STROBE; }
|
||||
#define read8inline(result) { \
|
||||
RD_ACTIVE; \
|
||||
DELAY7; \
|
||||
result = ((PINE & B01000000) << 1) | ((PIND & B10000000) >> 1) | \
|
||||
((PINC & B10000000) >> 2) | ((PINB & B11110000) >> 4) | \
|
||||
(PIND & B00010000); \
|
||||
RD_IDLE; }
|
||||
#define setWriteDirInline() { \
|
||||
DDRE |= B01000000; DDRD |= B10010000; \
|
||||
DDRC |= B10000000; DDRB |= B11110000; }
|
||||
#define setReadDirInline() { \
|
||||
DDRE &= ~B01000000; DDRD &= ~B10010000; \
|
||||
DDRC &= ~B10000000; DDRB &= ~B11110000; }
|
||||
|
||||
#else // Leonardo w/Breakout board
|
||||
|
||||
#define write8inline(d) { \
|
||||
uint8_t dr1 = (d) >> 1, dl1 = (d) << 1; \
|
||||
PORTE = (PORTE & B10111111) | (dr1 & B01000000); \
|
||||
PORTD = (PORTD & B01101100) | (dl1 & B10000000) | (((d) & B00001000)>>3) | \
|
||||
(dr1 & B00000010) | ((d) & B00010000); \
|
||||
PORTC = (PORTC & B10111111) | (dl1 & B01000000); \
|
||||
PORTB = (PORTB & B11001111) |(((d) & B00000011)<<4); \
|
||||
WR_STROBE; }
|
||||
|
||||
#define read8inline() (RD_STROBE, \
|
||||
(((PINE & B01000000) | (PIND & B00000010)) << 1) | \
|
||||
(((PINC & B01000000) | (PIND & B10000000)) >> 1) | \
|
||||
((PIND & B00000001)<<3) | ((PINB & B00110000)>>4) | (PIND & B00010000))
|
||||
#define setWriteDirInline() { \
|
||||
DDRE |= B01000000; DDRD |= B10010011; \
|
||||
DDRC |= B01000000; DDRB |= B00110000; }
|
||||
#define setReadDirInline() { \
|
||||
DDRE &= ~B01000000; DDRD &= ~B10010011; \
|
||||
DDRC &= ~B01000000; DDRB &= ~B00110000; }
|
||||
#define write8inline(d) { \
|
||||
uint8_t dr1 = (d) >> 1, dl1 = (d) << 1; \
|
||||
PORTE = (PORTE & B10111111) | (dr1 & B01000000); \
|
||||
PORTD = (PORTD & B01101100) | (dl1 & B10000000) | (((d) & B00001000)>>3) |\
|
||||
(dr1 & B00000010) | ((d) & B00010000); \
|
||||
PORTC = (PORTC & B10111111) | (dl1 & B01000000); \
|
||||
PORTB = (PORTB & B11001111) |(((d) & B00000011)<<4); \
|
||||
WR_STROBE; }
|
||||
#define read8inline(result) { \
|
||||
RD_ACTIVE; \
|
||||
DELAY7; \
|
||||
result = (((PINE & B01000000) | (PIND & B00000010)) << 1) | \
|
||||
(((PINC & B01000000) | (PIND & B10000000)) >> 1) | \
|
||||
((PIND & B00000001) << 3) | ((PINB & B00110000) >> 4) | \
|
||||
(PIND & B00010000); \
|
||||
RD_IDLE; }
|
||||
#define setWriteDirInline() { \
|
||||
DDRE |= B01000000; DDRD |= B10010011; \
|
||||
DDRC |= B01000000; DDRB |= B00110000; }
|
||||
#define setReadDirInline() { \
|
||||
DDRE &= ~B01000000; DDRD &= ~B10010011; \
|
||||
DDRC &= ~B01000000; DDRB &= ~B00110000; }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -255,10 +288,7 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Data read and write strobes, ~2 instructions and always inline
|
||||
#ifndef RD_STROBE
|
||||
#define RD_STROBE RD_ACTIVE, RD_IDLE
|
||||
#endif
|
||||
// Data write strobe, ~2 instructions and always inline
|
||||
#define WR_STROBE { WR_ACTIVE; WR_IDLE; }
|
||||
|
||||
// These higher-level operations are usually functionalized,
|
||||
|
||||
Reference in New Issue
Block a user