// Illustration of ILI 9431 readback bug over SPI.// See notes at the bottom.
#include "SPI.h"
#include "ILI9341_t3.h"
ILI9341_t3 d = ILI9341_t3(10, 9);
uint16_t buf[80];
uint16_t good[512];
uint16_t bad[512];
uint8_t diag[5];
// http://en.wikipedia.org/wiki/Hamming_distance
int hamming_distance(unsigned x, unsigned y) {
int dist;
unsigned val;
dist = 0;
val = x ^ y;
// Count the number of bits set
while (val != 0) {
// A bit is set, so increment the count and clear the bit
dist++;
val &= val - 1;
}
// Return the number of differing bits
return dist;
}
// Read diagnostics. Only appears to work when Teensy CPU is 72 Mhz or 24 Mhz.
void readdiag() {
diag[0] = d.readcommand8(ILI9341_RDMODE);
diag[1] = d.readcommand8(ILI9341_RDMADCTL);
diag[2] = d.readcommand8(ILI9341_RDPIXFMT);
diag[3] = d.readcommand8(ILI9341_RDIMGFMT);
diag[4] = d.readcommand8(ILI9341_RDSELFDIAG);
}
void printdiag() {
d.setCursor(0, 4);
d.print("Display Power Mode: 0x"); d.println(diag[0], HEX);
d.print("MADCTL Mode: 0x"); d.println(diag[1], HEX);
d.print("Pixel Format: 0x"); d.println(diag[2], HEX);
d.print("Image Format: 0x"); d.println(diag[3], HEX);
d.print("Self Diagnostic: 0x"); d.println(diag[4], HEX);
}
// Draw four rows.
// Row 1 has the diagnostic codes.
// Rows 2, 3 and 4 should match.
// Row 2 is a gradient created with drawFastVLine().
// Row 3 is a gradient created with writeRect().
// Row 4 is a gradient created with readPixel() and
// writeRect().
void draw() {
// Draw row labels.
for (int i = 1; i <= 4; ++i) {
int y = 60 * (i - 1) + 26;
d.setCursor(288, y);
d.print(i);
d.drawFastHLine(256, 60 * i, 320 - 256, ILI9341_WHITE);
}
// Draw three gradients that should match.
for (int x = 0; x < 256; ++x) {
// Row 2: Draw one column of a gradient with drawFastVLine().
uint16_t c = d.color565(x, x, x);
d.drawFastVLine(x, 60, 60, c);
// Row 3: Draw one column of a gradient with writeRect().
for (int i = 0; i < 60; ++i) buf[i] = c;
d.writeRect(x, 120, 1, 60, buf);
// Row 4: Draw one column of a gradient with readPixel() and writeRect().
// Attempting to copy from first row - readPixel() gets (usually) white trash
// roughly 0.5% of the time.
uint16_t r = d.readPixel(x, 61);
// // Instead take the majority of three reads.
// for (int i=0;i<2;++i) {
// uint16_t r2 = d.readPixel(x, 61);
// if (r == r2) break;
// r = r2;
// }
for (int i = 0; i < 60; ++i) buf[i] = r;
d.writeRect(x, 180, 1, 60, buf);
// Save these to memory in case Serial interferes somehow.
good[x] = c;
bad[x] = r;
}
// Error log. There should't be any messages unless there are errors.
for (int x = 0; x < 256; ++x) {
if (good[x] != bad[x]) {
Serial.print(x, HEX);
Serial.print(" ");
Serial.print(good[x], HEX);
Serial.print(" ");
Serial.print(d.readPixel(x, 0), HEX);
Serial.print(" ");
// These values should match the good column. They're not even deterministic!
Serial.print(bad[x], HEX);
Serial.print(" ");
// The Hamming distance is usually 1 or 2, but occasionally as large as 8.
Serial.println(hamming_distance(good[x], bad[x]));
}
}
}
void setup() {
// Set a couple of outputs for flagging extraneous SPI::endTransaction() calls.
pinMode(17, OUTPUT);
pinMode(18, OUTPUT);
digitalWriteFast(18, 0);
digitalWriteFast(17, 0);
// Set up the searial console for error logging.
Serial.begin(9600);
uint32_t count = 10000;
while (!Serial && count--) delay(1);
Serial.println("Read Pixel Test");
d.begin();
d.setRotation(1);
readdiag();
d.fillScreen(ILI9341_BLACK);
}
void loop() {
draw();
readdiag();
printdiag();
}
// In ILI9341_t3::readRect, adding a 4us delay before waitFifoEmpty() and eliminating
// the dummy read makes it function correctly 72Mhz and 24Mhz, optimized or not.
// Display Power Mode: 0x9C
// MADCTL Mode: 0x28
// Pixel Format: 0x5
// Image Format: 0x0
// Self Diagnostic: 0x0
//
// However if we set the Teensy clock to another value, the display and the diagnostics get
// messed up. The display shows random errors in row 4. The diagnostics report:
// 96MHz or 48MHz optimized or non-optimized
// Display Power Mode: 0xDE
// MADCTL Mode: 0x3C
// Pixel Format: 0x7
// Image Format: 0x0
// Self Diagnostic: 0xE0
// No extra SPI.endTransaction() calls were detected. No extra SPI.beginTransaction()
// calls were inferred because no deadlock was observed.
//
// Triplicating the readPixel() call significantly reduced the appearance of errors.
// Discarding the first read doesn't appear to help.