Compare commits

...

7 commits

Author SHA1 Message Date
Phillip Burgess
167e9364be Trying to get CCL working, not there yet 2018-06-21 22:29:18 -07:00
Phillip Burgess
bdcfb20734 Tweak pushColors() for SAMD51, add non-DMA option to wobble example 2018-06-21 18:40:57 -07:00
Phillip Burgess
c542e168f3 Added 'wobble' example -- better example of pushColorsDMA() 2018-06-21 18:22:10 -07:00
Phillip Burgess
d5390a973a Add pushColorsDMA() and example use in tftbmp.pde 2018-06-21 17:42:36 -07:00
Phillip Burgess
aef2d6d469 DMA working, BUT with gotchas, see comments in examples! 2018-06-21 13:43:51 -07:00
Phillip Burgess
c69ffb9866 DMA working for flood() function if hi & lo bytes match 2018-06-20 17:38:11 -07:00
Phillip Burgess
b0debeeeef Initial SAMD51 work
Breakout only (no shield), data pins are hardcoded, works on ItsyBitsy M4.
2018-06-19 22:10:25 -07:00
11 changed files with 859 additions and 1269 deletions

View file

@ -33,6 +33,51 @@
#include "registers.h"
#if defined(__SAMD51__)
#include <Adafruit_ZeroDMA.h>
#include "utility/dma.h"
#define TIMERNUM 3
#if TIMERNUM == 0
#define TIMER TC0
#define IRQN TC0_IRQn
#define IRQ_HANDLER TC0_Handler
#define TIMER_GCLK_ID TC0_GCLK_ID
#define TIMER_EVU EVSYS_ID_USER_TC0_EVU
#elif TIMERNUM == 1
#define TIMER TC1
#define IRQN TC1_IRQn
#define IRQ_HANDLER TC1_Handler
#define TIMER_GCLK_ID TC1_GCLK_ID
#define TIMER_EVU EVSYS_ID_USER_TC1_EVU
#elif TIMERNUM == 2
#define TIMER TC2
#define IRQN TC2_IRQn
#define IRQ_HANDLER TC2_Handler
#define TIMER_GCLK_ID TC2_GCLK_ID
#define TIMER_EVU EVSYS_ID_USER_TC2_EVU
#elif TIMERNUM == 3
#define TIMER TC3
#define IRQN TC3_IRQn
#define IRQ_HANDLER TC3_Handler
#define TIMER_GCLK_ID TC3_GCLK_ID
#define TIMER_EVU EVSYS_ID_USER_TC3_EVU
#endif
#define clockpin 4 // ItsyBitsy M4
static Adafruit_ZeroDMA myDMA;
static ZeroDMAstatus stat;
static DmacDescriptor *desc;
static volatile bool transfer_is_done = true;
static void dma_callback(Adafruit_ZeroDMA *dma) {
transfer_is_done = true;
}
#endif
// Constructor for breakout board (configurable LCD control lines).
// Can still use this w/shield, but parameters are ignored.
Adafruit_TFTLCD::Adafruit_TFTLCD(
@ -47,13 +92,36 @@ Adafruit_TFTLCD::Adafruit_TFTLCD(
cdPort = portOutputRegister(digitalPinToPort(cd));
wrPort = portOutputRegister(digitalPinToPort(wr));
rdPort = portOutputRegister(digitalPinToPort(rd));
#endif
#if defined(__SAM3X8E__)
#elif defined(__SAM3X8E__)
csPort = digitalPinToPort(cs);
cdPort = digitalPinToPort(cd);
wrPort = digitalPinToPort(wr);
rdPort = digitalPinToPort(rd);
#elif defined(__SAMD51__)
csPortSet = &(PORT->Group[g_APinDescription[cs].ulPort].OUTSET.reg);
csPortClr = &(PORT->Group[g_APinDescription[cs].ulPort].OUTCLR.reg);
cdPortSet = &(PORT->Group[g_APinDescription[cd].ulPort].OUTSET.reg);
cdPortClr = &(PORT->Group[g_APinDescription[cd].ulPort].OUTCLR.reg);
wrPortSet = &(PORT->Group[g_APinDescription[wr].ulPort].OUTSET.reg);
wrPortClr = &(PORT->Group[g_APinDescription[wr].ulPort].OUTCLR.reg);
rdPortSet = &(PORT->Group[g_APinDescription[rd].ulPort].OUTSET.reg);
rdPortClr = &(PORT->Group[g_APinDescription[rd].ulPort].OUTCLR.reg);
// Temporary - pin 0 determines which PORT register to use
volatile uint32_t *r = &(PORT->Group[g_APinDescription[0].ulPort].OUT.reg);
writePort = (volatile uint8_t *)r + 2;
r = &(PORT->Group[g_APinDescription[0].ulPort].IN.reg);
readPort = (volatile uint8_t *)r + 2;
r = &(PORT->Group[g_APinDescription[0].ulPort].DIRSET.reg);
dirSet = (volatile uint8_t *)r + 2;
r = &(PORT->Group[g_APinDescription[0].ulPort].DIRCLR.reg);
dirClr = (volatile uint8_t *)r + 2;
#endif
#if defined(__SAMD51__)
csPinMask = digitalPinToBitMask(cs);
cdPinMask = digitalPinToBitMask(cd);
wrPinMask = digitalPinToBitMask(wr);
rdPinMask = digitalPinToBitMask(rd);
#else
csPinSet = digitalPinToBitMask(cs);
cdPinSet = digitalPinToBitMask(cd);
wrPinSet = digitalPinToBitMask(wr);
@ -62,22 +130,28 @@ Adafruit_TFTLCD::Adafruit_TFTLCD(
cdPinUnset = ~cdPinSet;
wrPinUnset = ~wrPinSet;
rdPinUnset = ~rdPinSet;
#endif
#ifdef __AVR__
*csPort |= csPinSet; // Set all control bits to HIGH (idle)
*cdPort |= cdPinSet; // Signals are ACTIVE LOW
*wrPort |= wrPinSet;
*rdPort |= rdPinSet;
#endif
#if defined(__SAM3X8E__)
#elif defined(__SAM3X8E__)
csPort->PIO_SODR |= csPinSet; // Set all control bits to HIGH (idle)
cdPort->PIO_SODR |= cdPinSet; // Signals are ACTIVE LOW
wrPort->PIO_SODR |= wrPinSet;
rdPort->PIO_SODR |= rdPinSet;
#elif defined(__SAMD51__)
*csPortSet = csPinMask; // Set all control bits to HIGH (idle)
*cdPortSet = cdPinMask; // Signals are ACTIVE LOW
*wrPortSet = wrPinMask;
// *wrPortClr = wrPinMask;
*rdPortSet = rdPinMask;
#endif
pinMode(cs, OUTPUT); // Enable outputs
pinMode(cd, OUTPUT);
pinMode(wr, OUTPUT);
pinMode(rd, OUTPUT);
pinMode(cd, OUTPUT);
if(reset) {
digitalWrite(reset, HIGH);
pinMode(reset, OUTPUT);
@ -294,7 +368,7 @@ void Adafruit_TFTLCD::begin(uint16_t id) {
writeRegister8(ILI9341_DISPLAYON, 0);
delay(500);
setAddrWindow(0, 0, TFTWIDTH-1, TFTHEIGHT-1);
return;
// return;
} else if (id == 0x8357) {
// HX8357D
@ -321,7 +395,7 @@ void Adafruit_TFTLCD::begin(uint16_t id) {
}
}
return;
// return;
} else if(id == 0x7575) {
@ -339,8 +413,152 @@ void Adafruit_TFTLCD::begin(uint16_t id) {
} else {
driver = ID_UNKNOWN;
return;
// return;
}
#if defined(__SAMD51__)
// Do insane timer/PWM/DMA init here
// Write-strobe pin will NEED to be on a PWM-suitable output!
// TIMER STUFF
// Set up generic clock gen 2 as source for TC4
// Datasheet recommends setting GENCTRL register in a single write,
// so a temp value is used here to more easily construct a value.
GCLK_GENCTRL_Type genctrl;
genctrl.bit.SRC = GCLK_GENCTRL_SRC_DPLL0_Val; // 120 MHz source
genctrl.bit.GENEN = 1; // Enable
genctrl.bit.OE = 1;
genctrl.bit.DIVSEL = 0; // Do not divide clock source
genctrl.bit.DIV = 0;
GCLK->GENCTRL[2].reg = genctrl.reg;
while(GCLK->SYNCBUSY.bit.GENCTRL1 == 1);
GCLK->PCHCTRL[TIMER_GCLK_ID].bit.CHEN = 0;
while(GCLK->PCHCTRL[TIMER_GCLK_ID].bit.CHEN); // Wait for disable
GCLK_PCHCTRL_Type pchctrl;
pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK2_Val;
pchctrl.bit.CHEN = 1;
GCLK->PCHCTRL[TIMER_GCLK_ID].reg = pchctrl.reg;
while(!GCLK->PCHCTRL[TIMER_GCLK_ID].bit.CHEN); // Wait for enable
// Set up event system off same clock
GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 0;
while(GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); // Wait for disable
pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK2_Val;
pchctrl.bit.CHEN = 1;
GCLK->PCHCTRL[EVSYS_GCLK_ID_0].reg = pchctrl.reg;
while(!GCLK->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN); // Wait for enable
MCLK->APBBMASK.bit.EVSYS_ = 1; // Enable event system clock
// Configure timer for 8-bit normal PWM mode
// Counter must first be disabled to configure it
TIMER->COUNT8.CTRLA.bit.ENABLE = 0;
while(TIMER->COUNT8.SYNCBUSY.bit.STATUS);
TIMER->COUNT8.WAVE.bit.WAVEGEN = 2; // Normal PWM mode (NPWM)
TIMER->COUNT8.CTRLA.bit.MODE = 1; // 8-bit counter mode
TIMER->COUNT8.CTRLA.bit.PRESCALER = 0; // 1:1 clock prescale
while(TIMER->COUNT8.SYNCBUSY.bit.STATUS);
//TIMER->COUNT8.CTRLBSET.bit.DIR = 1; // Count DOWN
TIMER->COUNT8.CTRLBCLR.bit.DIR = 1; // Count UP
while(TIMER->COUNT8.SYNCBUSY.bit.CTRLB);
TIMER->COUNT8.CTRLBSET.bit.ONESHOT = 1; // One-shot operation
while(TIMER->COUNT8.SYNCBUSY.bit.CTRLB);
TIMER->COUNT8.PER.reg = 3; // PWM top value
while(TIMER->COUNT8.SYNCBUSY.bit.PER);
TIMER->COUNT8.CC[0].reg = 2; // Compare value for channel 0
while(TIMER->COUNT8.SYNCBUSY.bit.CC0);
TIMER->COUNT8.EVCTRL.bit.TCEI = 1; // Enable async input events
TIMER->COUNT8.EVCTRL.bit.EVACT = 1; // Event action = start/restart/retrigger
//TIMER->COUNT8.DRVCTRL.bit.INVEN0 = 1; // Invert output
// Enable TCx
TIMER->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE;
while(TIMER->COUNT8.SYNCBUSY.bit.STATUS);
// CCL STUFF
// Enable CCL bus clock (CLK_CCL_APB)
MCLK->APBCMASK.bit.CCL_ = 1; // Enable CCL clock
// Generic clock (GCLK_CCL) is needed for input events, filter,
// edge detection or sequential logic (i.e. not needed here?)
GCLK->PCHCTRL[CCL_GCLK_ID].bit.CHEN = 0;
while(GCLK->PCHCTRL[CCL_GCLK_ID].bit.CHEN); // Wait for disable
pchctrl.bit.GEN = GCLK_PCHCTRL_GEN_GCLK2_Val;
pchctrl.bit.CHEN = 1;
GCLK->PCHCTRL[CCL_GCLK_ID].reg = pchctrl.reg;
while(!GCLK->PCHCTRL[CCL_GCLK_ID].bit.CHEN); // Wait for enable
// CCL/OUT[0] = PA07 (D2), PA19 (D9), PB02 (NA), PB23 (MISO)
// CCL/OUT[1] = PA11 (NA), PA31 (SWDIO), PB11 (NA)
// CCL/OUT[2] = PB09 (A3), PA25 (NA)
// CCL/OUT[3] = PB17 (NA)
CCL->CTRL.bit.SWRST = 1; // Reset CCL registers to defaults
CCL->CTRL.bit.ENABLE = 1; // Enable CCL
// LUT control X register can only be written when disabled
CCL->LUTCTRL[TIMERNUM].bit.ENABLE = 0;
//CCL->LUTCTRL[TIMERNUM].bit.FILTSEL = 2; // Filter enabled
CCL->LUTCTRL[TIMERNUM].bit.FILTSEL = 0; // No filter
CCL->LUTCTRL[TIMERNUM].bit.INSEL0 = 6; // TC input source
CCL->LUTCTRL[TIMERNUM].bit.INSEL1 = 0; // MASK
CCL->LUTCTRL[TIMERNUM].bit.INSEL2 = 0; // MASK
CCL->LUTCTRL[TIMERNUM].bit.TRUTH = 0b01010101; // Invert
CCL->LUTCTRL[TIMERNUM].bit.ENABLE = 1;
#if TIMERNUM == 0
pinMode(2, OUTPUT);
pinPeripheral(2, PIO_CCL);
#elif TIMERNUM == 2
pinMode(A3, OUTPUT);
pinPeripheral(A3, PIO_CCL);
#endif
// EVENTS STUFF
EVSYS->USER[TIMER_EVU].reg = 1; // Connect Timer EVU to ch 0 (value is +1)
// Datasheet recommends single write operation; reg instead of bit
// Also datasheet: PATH bits must be zero when using async!
EVSYS_CHANNEL_Type ev;
ev.reg = 0;
ev.bit.PATH = 2; // Asynchronous
ev.bit.EVGEN = 0x22; // DMA channel 0
EVSYS->Channel[0].CHANNEL.reg = ev.reg;
// DMA STUFF
stat = myDMA.allocate();
myDMA.printStatus(stat);
uint8_t foo;
desc = myDMA.addDescriptor(
(void *)&foo, // move data from here
(void *)writePort, // to here
256, // this many...
DMA_BEAT_SIZE_BYTE, // bytes/hword/words
false, // increment source addr?
false); // increment dest addr?
desc->BTCTRL.bit.EVOSEL = 0x3; // Event strobe on beat transfer
DMAC->Channel[0].CHEVCTRL.bit.EVOE = 1; // Enable event output
DMAC->Channel[0].CHEVCTRL.bit.EVOMODE = 0; // Use EVOSEL output selection
myDMA.setCallback(dma_callback);
#endif
}
void Adafruit_TFTLCD::reset(void) {
@ -482,9 +700,32 @@ void Adafruit_TFTLCD::flood(uint16_t color, uint32_t len) {
} else {
write8(0x22); // Write data to GRAM
}
CD_DATA;
#if defined(__SAMD51__)
if(hi == lo) {
pinPeripheral(clockpin, PIO_TIMER);
desc->SRCADDR.reg = (uint32_t)&lo;
desc->BTCTRL.bit.SRCINC = 0;
uint32_t bytesToGo = len * 2;
uint16_t bytesThisPass;
// BTCNT is a 16-bit value, so large fills may require multiple DMA xfers
while(bytesToGo > 0) {
if(bytesToGo > 65535) bytesThisPass = 65535;
else bytesThisPass = bytesToGo;
desc->BTCNT.reg = bytesThisPass;
transfer_is_done = false;
stat = myDMA.startJob();
myDMA.trigger();
while(!transfer_is_done);
bytesToGo -= bytesThisPass;
}
pinPeripheral(clockpin, PIO_OUTPUT);
} else {
#endif
// Write first pixel normally, decrement counter by 1
CD_DATA;
//CD_DATA;
write8(hi);
write8(lo);
len--;
@ -518,6 +759,11 @@ void Adafruit_TFTLCD::flood(uint16_t color, uint32_t len) {
write8(lo);
}
}
#if defined(__SAMD51__)
}
#endif
CS_IDLE;
}
@ -627,7 +873,6 @@ void Adafruit_TFTLCD::fillScreen(uint16_t color) {
// 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);
}
@ -692,20 +937,50 @@ void Adafruit_TFTLCD::drawPixel(int16_t x, int16_t y, uint16_t color) {
// 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).
#if defined(__SAMD51__)
void Adafruit_TFTLCD::pushColors(uint16_t *data, uint16_t len, boolean first) {
#else
void Adafruit_TFTLCD::pushColors(uint16_t *data, uint8_t len, boolean first) {
#endif
uint16_t color;
uint8_t hi, lo;
CS_ACTIVE;
if(first == true) { // Issue GRAM write command only on first call
CD_COMMAND;
if(driver == ID_932X) write8(0x00);
if ((driver == ID_9341) || (driver == ID_HX8357D)){
if (driver == ID_9341) {
write8(0x2C);
} else if (driver == ID_932X) {
write8(0x00); // High byte of GRAM register...
write8(0x22); // Write data to GRAM
} else if (driver == ID_HX8357D) {
write8(HX8357_RAMWR);
} else {
write8(0x22);
write8(0x22); // Write data to GRAM
}
}
CD_DATA;
#if defined(__SAMD51__)
pinPeripheral(clockpin, PIO_TIMER);
desc->BTCTRL.bit.SRCINC = 1;
uint8_t *dataPtr = (uint8_t *)data; // -> 1st byte of data
uint32_t bytesToGo = len * 2;
uint16_t bytesThisPass;
// BTCNT is a 16-bit value, so large fills may require multiple DMA xfers
while(bytesToGo > 0) {
if(bytesToGo > 65535) bytesThisPass = 65535;
else bytesThisPass = bytesToGo;
desc->SRCADDR.reg = (uint32_t)dataPtr + bytesThisPass;
desc->BTCNT.reg = bytesThisPass;
transfer_is_done = false;
stat = myDMA.startJob();
myDMA.trigger();
while(!transfer_is_done);
bytesToGo -= bytesThisPass;
dataPtr += bytesThisPass;
}
pinPeripheral(clockpin, PIO_OUTPUT);
#else
while(len--) {
color = *data++;
hi = color >> 8; // Don't simplify or merge these
@ -713,6 +988,66 @@ void Adafruit_TFTLCD::pushColors(uint16_t *data, uint8_t len, boolean first) {
write8(hi); // going on.
write8(lo);
}
#endif
CS_IDLE;
}
void Adafruit_TFTLCD::pushColorsDMA(
uint32_t bytesToGo,
uint8_t *buffer,
uint16_t bufSize,
void (*callback)(uint8_t *dest, uint16_t len)) {
CS_ACTIVE;
CD_COMMAND;
if(driver == ID_9341) {
write8(0x2C);
} else if(driver == ID_932X) {
write8(0x00); // High byte of GRAM register...
write8(0x22); // Write data to GRAM
} else if (driver == ID_HX8357D) {
write8(HX8357_RAMWR);
} else {
write8(0x22); // Write data to GRAM
}
CD_DATA;
// Buffer passed in should be 2X bufSize bytes...
uint8_t *buf[2];
buf[0] = buffer; // First half of buffer
buf[1] = buf[0] + bufSize; // Second half
uint8_t idx = 2; // Active buffer 0/1 (2 = first pass; no xfer)
pinPeripheral(clockpin, PIO_TIMER);
desc->BTCTRL.bit.SRCINC = 1;
uint16_t bytesThisPass;
while(bytesToGo > 0) {
if(idx < 2) {
// Wait for prior transfer to finish
while(!transfer_is_done);
// Send from buf[idx]
desc->SRCADDR.reg = (uint32_t)buf[idx] + bytesThisPass;
desc->BTCNT.reg = bytesThisPass;
transfer_is_done = false;
stat = myDMA.startJob();
myDMA.trigger();
bytesToGo -= bytesThisPass; // Data sent
idx = 1 - idx; // Toggle idx so data is loaded into alt buffer
} else {
// First pass, no xfer, just load...
idx = 0;
}
// Load next data (if needed)
if(bytesToGo) {
if(bytesToGo > bufSize) bytesThisPass = bufSize;
else bytesThisPass = bytesToGo;
(*callback)(buf[idx], bytesThisPass);
}
}
// Wait for last transfer to finish
while(!transfer_is_done);
pinPeripheral(clockpin, PIO_OUTPUT);
CS_IDLE;
}

View file

@ -38,7 +38,14 @@ class Adafruit_TFTLCD : public Adafruit_GFX {
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);
#if defined(__SAMD51__)
void pushColors(uint16_t *data, uint16_t len, boolean first);
#else
void pushColors(uint16_t *data, uint8_t len, boolean first);
#endif
void pushColorsDMA(uint32_t totalBytes, uint8_t *buffer,
uint16_t bufSize, void (*callback)(uint8_t *dest, uint16_t len));
uint16_t color565(uint8_t r, uint8_t g, uint8_t b),
readPixel(int16_t x, int16_t y),
@ -86,12 +93,18 @@ class Adafruit_TFTLCD : public Adafruit_GFX {
uint8_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
csPinUnset, cdPinUnset, wrPinUnset, rdPinUnset,
_reset;
#endif
#if defined(__SAM3X8E__)
#elif defined(__SAM3X8E__)
Pio *csPort , *cdPort , *wrPort , *rdPort;
uint32_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
csPinUnset, cdPinUnset, wrPinUnset, rdPinUnset,
_reset;
#elif defined(__SAMD51__)
volatile uint32_t *csPortSet , *cdPortSet , *wrPortSet , *rdPortSet,
*csPortClr , *cdPortClr , *wrPortClr , *rdPortClr;
uint32_t csPinMask , cdPinMask , wrPinMask , rdPinMask,
_reset;
volatile uint8_t *writePort, *readPort, *dirSet, *dirClr;
#endif
#endif

84
examples/graphicstest/graphicstest.pde Executable file → Normal file
View file

@ -1,32 +1,39 @@
// IMPORTANT: Adafruit_TFTLCD LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.
// SEE RELEVANT COMMENTS IN Adafruit_TFTLCD.h FOR SETUP.
// Graphics test rigged specifically for the SAMD21 branch
// of TFTLCD and the ItsyBitsy M4 board. TFTLCD lib MUST be
// configured for the breakout board option, plus there's
// some wiring shenanigans...
// LCD_WR MUST go to pin D4, because we're using a specific
// timer/counter for PWM output. The pin # could be changed
// IF a corresponding timer change is made in the SAMD21 TFTLIB.
// One of two additional wiring changes MUST be made. Either:
// LCD_WR MUST go through an inverter (e.g. 74HC04)
// -or-
// The TFT 'CS' pin MUST be tied HIGH (ignoring LCD_CS setting)
// If you opt for this latter arrangement, you CANNOT read the
// device ID from the display (or anything else) -- see setup()
// where 'identifier' is hardcoded;
// Data pins are as follows:
// D0 connects to digital pin 0 (Notice these are
// D1 connects to digital pin 1 NOT in order!)
// D2 connects to digital pin 7
// D3 connects to digital pin 9
// D4 connects to digital pin 10
// D5 connects to digital pin 11
// D6 connects to digital pin 13
// D7 connects to digital pin 12
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
// double up the pins with the touch screen (see the TFT paint example).
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_CS A3 // Chip Select (see notes above)
#define LCD_CD A2 // Command/Data
#define LCD_RD A0 // LCD Read strobe
#define LCD_WR 4 // LCD Write strobe (see notes above)
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin
// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
// For the Arduino Uno, Duemilanove, Diecimila, etc.:
// D0 connects to digital pin 8 (Notice these are
// D1 connects to digital pin 9 NOT in order!)
// D2 connects to digital pin 2
// D3 connects to digital pin 3
// D4 connects to digital pin 4
// D5 connects to digital pin 5
// D6 connects to digital pin 6
// D7 connects to digital pin 7
// For the Arduino Mega, use digital pins 22 through 29
// (on the 2-row header at the end of the board).
#define LCD_RESET A4 // Alternately just connect to Arduino's reset pin
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
@ -39,14 +46,10 @@
#define WHITE 0xFFFF
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// Adafruit_TFTLCD tft;
void setup(void) {
Serial.begin(9600);
Serial.println(F("TFT LCD test"));
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
Serial.println(F("Using Adafruit 2.8\" TFT Arduino Shield Pinout"));
#else
@ -59,6 +62,10 @@ void setup(void) {
uint16_t identifier = tft.readID();
// SEE NOTES ABOVE - this is necessary IF using the
// hard-wired CS (and no inverter) option.
identifier = 0x9341;
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
@ -78,11 +85,30 @@ void setup(void) {
Serial.println(F("If using the breakout board, it should NOT be #defined!"));
Serial.println(F("Also if using the breakout, double-check that all wiring"));
Serial.println(F("matches the tutorial."));
return;
}
tft.begin(identifier);
#if 0
// Test frame rate:
uint32_t startTime = millis();
uint32_t frames = 0;
for(;;) {
tft.fillScreen(0x0000);
frames++;
// delay(500);
tft.fillScreen(0xFFFF);
frames++;
// delay(500);
if(!(frames & 0xFF)) {
uint32_t elapsed = (millis() - startTime) / 1000;
if(elapsed > 0) {
Serial.println(frames / elapsed);
}
}
}
#endif
Serial.println(F("Benchmark Time (microseconds)"));
Serial.print(F("Screen fill "));

View file

@ -1,223 +0,0 @@
// IMPORTANT: Adafruit_TFTLCD LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.
// SEE RELEVANT COMMENTS IN Adafruit_TFTLCD.h FOR SETUP.
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
// double up the pins with the touch screen (see the TFT paint example).
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin
// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
// For the Arduino Uno, Duemilanove, Diecimila, etc.:
// D0 connects to digital pin 8 (Notice these are
// D1 connects to digital pin 9 NOT in order!)
// D2 connects to digital pin 2
// D3 connects to digital pin 3
// D4 connects to digital pin 4
// D5 connects to digital pin 5
// D6 connects to digital pin 6
// D7 connects to digital pin 7
// For the Arduino Mega, use digital pins 22 through 29
// (on the 2-row header at the end of the board).
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
// If using the shield, all control and data lines are fixed, and
// a simpler declaration can optionally be used:
// Adafruit_TFTLCD tft;
void setup(void) {
Serial.begin(9600);
Serial.println(F("TFT LCD test"));
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
Serial.println(F("Using Adafruit 2.8\" TFT Arduino Shield Pinout"));
#else
Serial.println(F("Using Adafruit 2.8\" TFT Breakout Board Pinout"));
#endif
tft.reset();
uint16_t identifier = tft.readID();
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
Serial.println(F("Found ILI9328 LCD driver"));
} else if(identifier == 0x7575) {
Serial.println(F("Found HX8347G LCD driver"));
} else if(identifier == 0x9341) {
Serial.println(F("Found ILI9341 LCD driver"));
} else if(identifier == 0x8357) {
Serial.println(F("Found HX8357D LCD driver"));
} else {
Serial.print(F("Unknown LCD driver chip: "));
Serial.println(identifier, HEX);
Serial.println(F("If using the Adafruit 2.8\" TFT Arduino shield, the line:"));
Serial.println(F(" #define USE_ADAFRUIT_SHIELD_PINOUT"));
Serial.println(F("should appear in the library header (Adafruit_TFT.h)."));
Serial.println(F("If using the breakout board, it should NOT be #defined!"));
Serial.println(F("Also if using the breakout, double-check that all wiring"));
Serial.println(F("matches the tutorial."));
return;
}
tft.begin(identifier);
tft.fillScreen(BLACK);
Serial.println(F("This is a test of the rotation capabilities of the TFT library!"));
Serial.println(F("Press <SEND> (or type a character) to advance"));
}
void loop(void) {
rotatePixel();
rotateLine();
rotateFastline();
rotateDrawrect();
rotateFillrect();
rotateDrawcircle();
rotateFillcircle();
rotateText();
}
void rotateText() {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.setCursor(0, 30);
tft.setTextColor(RED);
tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(YELLOW);
tft.setTextSize(2);
tft.println("Hello World!");
tft.setTextColor(GREEN);
tft.setTextSize(3);
tft.println("Hello World!");
tft.setTextColor(BLUE);
tft.setTextSize(4);
tft.print(1234.567);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotateFillcircle(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.fillCircle(10, 30, 10, YELLOW);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotateDrawcircle(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.drawCircle(10, 30, 10, YELLOW);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotateFillrect(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.fillRect(10, 20, 10, 20, GREEN);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotateDrawrect(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.drawRect(10, 20, 10, 20, GREEN);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotateFastline(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.drawFastHLine(0, 20, tft.width(), RED);
tft.drawFastVLine(20, 0, tft.height(), BLUE);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotateLine(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.drawLine(tft.width()/2, tft.height()/2, 0, 0, RED);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}
void rotatePixel(void) {
for (uint8_t i=0; i<4; i++) {
tft.fillScreen(BLACK);
Serial.println(tft.getRotation(), DEC);
tft.drawPixel(10,20, RED);
while (!Serial.available());
Serial.read(); Serial.read(); Serial.read();
tft.setRotation(tft.getRotation()+1);
}
}

275
examples/tftbmp/tftbmp.pde Executable file → Normal file
View file

@ -1,53 +1,76 @@
// BMP-loading example specifically for the TFTLCD breakout board.
// If using the Arduino shield, use the tftbmp_shield.pde sketch instead!
// If using an Arduino Mega make sure to use its hardware SPI pins, OR make
// sure the SD library is configured for 'soft' SPI in the file Sd2Card.h.
// BMP-loading demo rigged specifically for the SAMD21 branch
// of TFTLCD and the ItsyBitsy M4 board. TFTLCD lib MUST be
// configured for the breakout board option, plus there's
// some wiring shenanigans...
// LCD_WR MUST go to pin D4, because we're using a specific
// timer/counter for PWM output. The pin # could be changed
// IF a corresponding timer change is made in the SAMD21 TFTLIB.
// One of two additional wiring changes MUST be made. Either:
// LCD_WR MUST go through an inverter (e.g. 74HC04)
// -or-
// The TFT 'CS' pin MUST be tied HIGH (ignoring LCD_CS setting)
// If you opt for this latter arrangement, you CANNOT read the
// device ID from the display (or anything else) -- see setup()
// where 'identifier' is hardcoded;
// Data pins are as follows:
// D0 connects to digital pin 0 (Notice these are
// D1 connects to digital pin 1 NOT in order!)
// D2 connects to digital pin 7
// D3 connects to digital pin 9
// D4 connects to digital pin 10
// D5 connects to digital pin 11
// D6 connects to digital pin 13
// D7 connects to digital pin 12
#include <SD.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <SD.h>
#include <SPI.h>
// The control pins for the LCD can be assigned to any digital or
// analog pins...but we'll use the analog pins as this allows us to
// double up the pins with the touch screen (see the TFT paint example).
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_CS A3 // Chip Select (see notes above)
#define LCD_CD A2 // Command/Data
#define LCD_RD A0 // LCD Read strobe
#define LCD_WR 4 // LCD Write strobe (see notes above)
// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
// For the Arduino Uno, Duemilanove, Diecimila, etc.:
// D0 connects to digital pin 8 (Notice these are
// D1 connects to digital pin 9 NOT in order!)
// D2 connects to digital pin 2
// D3 connects to digital pin 3
// D4 connects to digital pin 4
// D5 connects to digital pin 5
// D6 connects to digital pin 6
// D7 connects to digital pin 7
// For the Arduino Mega, use digital pins 22 through 29
// (on the 2-row header at the end of the board).
#define LCD_RESET A4 // Alternately just connect to Arduino's reset pin
// For Arduino Uno/Duemilanove, etc
// connect the SD card with DI going to pin 11, DO going to pin 12 and SCK going to pin 13 (standard)
// Then pin 10 goes to CS (or whatever you have set up)
#define SD_CS 10 // Set the chip select line to whatever you use (10 doesnt conflict with the library)
// DO NOT use the SD card slot on the TFT breakout -- it doesn't
// appear to work when using the parallel interface. Instead, a
// separate SD breakout is needed.
#define SD_CS A5 // SD card delect
// A switch or jumper on A1 selects DMA vs non-DMA BMP loading.
// There's really not a huge performance difference in this case
// just because the bottleneck is in the SD card access and color
// conversion operations...BUT...it does demonstrate how the
// pushColorsDMA() function works, and how to use a callback to
// load the next block of data while the current block is sent.
#define DMA_SELECT A1 // Hi/lo chooses DMA vs non-DMA DMA loader
// In the SD card, place 24 bit color BMP files (be sure they are 24-bit!)
// There are examples in the sketch folder
// our TFT wiring
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, A4);
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
void setup()
{
Serial.begin(9600);
while(!Serial);
pinMode(DMA_SELECT, INPUT_PULLUP);
tft.reset();
uint16_t identifier = tft.readID();
// SEE NOTES ABOVE - this is necessary IF using the
// hard-wired CS (and no inverter) option.
identifier = 0x9341;
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
@ -71,16 +94,23 @@ void setup()
}
tft.begin(identifier);
tft.fillScreen(0);
Serial.print(F("Initializing SD card..."));
if (!SD.begin(SD_CS)) {
Serial.println(F("failed!"));
return;
tft.fillScreen(0xF800);
for(;;);
}
Serial.println(F("OK!"));
Serial.println(F("OK!"));
tft.fillScreen(0x001F);
if(digitalRead(DMA_SELECT))
bmpDrawDMA("woof.bmp", 0, 0);
else
bmpDraw("woof.bmp", 0, 0);
delay(1000);
// delay(1000);
}
void loop()
@ -89,12 +119,39 @@ void loop()
tft.setRotation(i);
tft.fillScreen(0);
for(int j=0; j <= 200; j += 50) {
if(digitalRead(DMA_SELECT))
bmpDrawDMA("miniwoof.bmp", j, j);
else
bmpDraw("miniwoof.bmp", j, j);
}
delay(1000);
// delay(1000);
}
}
// Common functions/vars for both BMP loaders ------------------------------
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
// "Vanilla" (non-DMA) BMP Loader ------------------------------------------
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates. It's sped up
// by reading many pixels worth of data at a time
@ -103,10 +160,9 @@ void loop()
// makes loading a little faster. 20 pixels seems a
// good balance.
#define BUFFPIXEL 20
#define BUFFPIXEL 64
void bmpDraw(char *filename, int x, int y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
@ -122,6 +178,7 @@ void bmpDraw(char *filename, int x, int y) {
uint32_t pos = 0, startTime = millis();
uint8_t lcdidx = 0;
boolean first = true;
uint16_t col16;
if((x >= tft.width()) || (y >= tft.height())) return;
@ -208,7 +265,8 @@ void bmpDraw(char *filename, int x, int y) {
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
lcdbuffer[lcdidx++] = tft.color565(r,g,b);
col16 = tft.color565(r,g,b);
lcdbuffer[lcdidx++] = (col16 * 0x00010001) >> 8; // Flip hi/lo bytes
} // end pixel
} // end scanline
// Write any remaining data to LCD
@ -221,28 +279,141 @@ void bmpDraw(char *filename, int x, int y) {
} // end goodBmp
}
}
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1);
bmpFile.close();
if(!goodBmp) Serial.println(F("BMP format not recognized."));
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
// DMA BMP Loader ----------------------------------------------------------
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
// DMA buffer: 320 pixels max width, DMALINES height, 2 bytes/pixel, 2 bufs
// SD buffer: 320 pixels max width, one scanline
#define DMALINES 16
uint8_t dmabuf[DMALINES * 320 * 2 * 2];
uint8_t sdbuf[320 * 3];
File bmpFile;
uint32_t bmpImageoffset; // Start of image data in file
int lineNum, linesToGo; // Current, remaining lines to load
boolean flip; // BMP is stored bottom-to-top
int bmpHeight; // Uncropped height in pixels
int croppedWidth; // Cropped width in pixels
uint32_t rowSize; // Not always bmpWidth; may have padding
void bmpCallback(uint8_t *dest, uint16_t len) {
int row, col, linesThisPass;
uint8_t r, g, b, *ptr;
uint16_t col16;
uint32_t pos;
linesThisPass = (linesToGo > DMALINES) ? DMALINES : linesToGo;
for(row=0; row<linesThisPass; row++, lineNum++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - lineNum) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + lineNum * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
bmpFile.read(sdbuf, croppedWidth * 3); // Read scanline
ptr = sdbuf;
for(col=0; col<croppedWidth; col++) { // For each column...
// Convert pixel from BMP to TFT format
b = *ptr++;
g = *ptr++;
r = *ptr++;
col16 = tft.color565(r,g,b);
*dest++ = col16 >> 8; // High byte
*dest++ = col16; // Low byte
} // end pixel
} // end scanline
linesToGo -= linesThisPass;
}
void bmpDrawDMA(char *filename, int x, int y) {
int bmpWidth; // Image width in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
boolean goodBmp = false; // Set to true on valid header parse
int w, h;
uint32_t startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print(F("Loading image '"));
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.println(F("File not found"));
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.println(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print(F("Image size: "));
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
} else {
flip = true;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x+w-1, y+h-1);
croppedWidth = w;
lineNum = 0;
linesToGo = h;
tft.pushColorsDMA(w * h * 2, dmabuf, w * DMALINES * 2, bmpCallback);
Serial.print(F("Loaded in "));
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1);
bmpFile.close();
if(!goodBmp) Serial.println(F("BMP format not recognized."));
}

View file

@ -1,228 +0,0 @@
// BMP-loading example specifically for the TFTLCD Arduino shield.
// If using the breakout board, use the tftbmp.pde sketch instead!
// If using an Arduino Mega and your sheild does not use the ICSP header for
// SPI, make sure the SD library is configured for 'soft' SPI in the file Sd2Card.h.
// If in doubt, update the library to use 'soft' SPI.
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <SD.h>
// In the SD card, place 24 bit color BMP files (be sure they are 24-bit!)
// There are examples in the sketch folder
#define SD_CS 5 // Card select for shield use
Adafruit_TFTLCD tft;
uint8_t spi_save;
void setup()
{
Serial.begin(9600);
tft.reset();
uint16_t identifier = tft.readID();
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
Serial.println(F("Found ILI9328 LCD driver"));
} else if(identifier == 0x7575) {
Serial.println(F("Found HX8347G LCD driver"));
} else if(identifier == 0x9341) {
Serial.println(F("Found ILI9341 LCD driver"));
} else {
Serial.print(F("Unknown LCD driver chip: "));
Serial.println(identifier, HEX);
Serial.println(F("If using the Adafruit 2.8\" TFT Arduino shield, the line:"));
Serial.println(F(" #define USE_ADAFRUIT_SHIELD_PINOUT"));
Serial.println(F("should appear in the library header (Adafruit_TFT.h)."));
Serial.println(F("If using the breakout board, it should NOT be #defined!"));
Serial.println(F("Also if using the breakout, double-check that all wiring"));
Serial.println(F("matches the tutorial."));
return;
}
tft.begin(identifier);
Serial.print(F("Initializing SD card..."));
if (!SD.begin(SD_CS)) {
Serial.println(F("failed!"));
return;
}
Serial.println(F("OK!"));
spi_save = SPCR;
bmpDraw("woof.bmp", 0, 0);
delay(1000);
}
void loop()
{
for(int i = 0; i<4; i++) {
tft.setRotation(i);
tft.fillScreen(0);
for(int j=0; j <= 200; j += 50) {
bmpDraw("miniwoof.bmp", j, j);
}
delay(1000);
}
}
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates. It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel). Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster. 20 pixels seems a
// good balance.
#define BUFFPIXEL 20
void bmpDraw(char *filename, int x, int y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t lcdidx = 0;
boolean first = true;
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
SPCR = spi_save;
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print(F("Image size: "));
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
// Set TFT address window to clipped image bounds
SPCR = 0;
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
SPCR = spi_save;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col=0; col<w; col++) { // For each column...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
// Push LCD buffer to the display first
if(lcdidx > 0) {
SPCR = 0;
tft.pushColors(lcdbuffer, lcdidx, first);
lcdidx = 0;
first = false;
}
SPCR = spi_save;
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
lcdbuffer[lcdidx++] = tft.color565(r,g,b);
} // end pixel
} // end scanline
// Write any remaining data to LCD
if(lcdidx > 0) {
SPCR = 0;
tft.pushColors(lcdbuffer, lcdidx, first);
}
Serial.print(F("Loaded in "));
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println("BMP format not recognized.");
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}

View file

@ -1,209 +0,0 @@
// Paint example specifically for the TFTLCD breakout board.
// If using the Arduino shield, use the tftpaint_shield.pde sketch instead!
// DOES NOT CURRENTLY WORK ON ARDUINO LEONARDO
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
// When using the BREAKOUT BOARD only, use these 8 data lines to the LCD:
// For the Arduino Uno, Duemilanove, Diecimila, etc.:
// D0 connects to digital pin 8 (Notice these are
// D1 connects to digital pin 9 NOT in order!)
// D2 connects to digital pin 2
// D3 connects to digital pin 3
// D4 connects to digital pin 4
// D5 connects to digital pin 5
// D6 connects to digital pin 6
// D7 connects to digital pin 7
// For the Arduino Mega, use digital pins 22 through 29
// (on the 2-row header at the end of the board).
// D0 connects to digital pin 22
// D1 connects to digital pin 23
// D2 connects to digital pin 24
// D3 connects to digital pin 25
// D4 connects to digital pin 26
// D5 connects to digital pin 27
// D6 connects to digital pin 28
// D7 connects to digital pin 29
// For the Arduino Due, use digital pins 33 through 40
// (on the 2-row header at the end of the board).
// D0 connects to digital pin 33
// D1 connects to digital pin 34
// D2 connects to digital pin 35
// D3 connects to digital pin 36
// D4 connects to digital pin 37
// D5 connects to digital pin 38
// D6 connects to digital pin 39
// D7 connects to digital pin 40
#define YP A3 // must be an analog pin, use "An" notation!
#define XM A2 // must be an analog pin, use "An" notation!
#define YM 9 // can be a digital pin
#define XP 8 // can be a digital pin
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
// optional
#define LCD_RESET A4
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;
void setup(void) {
Serial.begin(9600);
Serial.println(F("Paint!"));
tft.reset();
uint16_t identifier = tft.readID();
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
Serial.println(F("Found ILI9328 LCD driver"));
} else if(identifier == 0x7575) {
Serial.println(F("Found HX8347G LCD driver"));
} else if(identifier == 0x9341) {
Serial.println(F("Found ILI9341 LCD driver"));
} else if(identifier == 0x8357) {
Serial.println(F("Found HX8357D LCD driver"));
} else {
Serial.print(F("Unknown LCD driver chip: "));
Serial.println(identifier, HEX);
Serial.println(F("If using the Adafruit 2.8\" TFT Arduino shield, the line:"));
Serial.println(F(" #define USE_ADAFRUIT_SHIELD_PINOUT"));
Serial.println(F("should appear in the library header (Adafruit_TFT.h)."));
Serial.println(F("If using the breakout board, it should NOT be #defined!"));
Serial.println(F("Also if using the breakout, double-check that all wiring"));
Serial.println(F("matches the tutorial."));
return;
}
tft.begin(identifier);
tft.fillScreen(BLACK);
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
// tft.fillRect(BOXSIZE*6, 0, BOXSIZE, BOXSIZE, WHITE);
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
currentcolor = RED;
pinMode(13, OUTPUT);
}
#define MINPRESSURE 10
#define MAXPRESSURE 1000
void loop()
{
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
// if sharing pins, you'll need to fix the directions of the touchscreen pins
//pinMode(XP, OUTPUT);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
//pinMode(YM, OUTPUT);
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
*/
if (p.y < (TS_MINY-5)) {
Serial.println("erase");
// press the bottom of the screen to erase
tft.fillRect(0, BOXSIZE, tft.width(), tft.height()-BOXSIZE, BLACK);
}
// scale from 0->1023 to tft.width
p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0);
/*
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
*/
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
if (oldcolor == GREEN) tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
if (oldcolor == CYAN) tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
if (oldcolor == BLUE) tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}
}

View file

@ -1,264 +0,0 @@
#ifndef FONT5X7_H
#define FONT5X7_H
// standard ascii 5x7 font
static unsigned char font[] = {
0x00, 0x00, 0x00, 0x00, 0x00,
0x3E, 0x5B, 0x4F, 0x5B, 0x3E,
0x3E, 0x6B, 0x4F, 0x6B, 0x3E,
0x1C, 0x3E, 0x7C, 0x3E, 0x1C,
0x18, 0x3C, 0x7E, 0x3C, 0x18,
0x1C, 0x57, 0x7D, 0x57, 0x1C,
0x1C, 0x5E, 0x7F, 0x5E, 0x1C,
0x00, 0x18, 0x3C, 0x18, 0x00,
0xFF, 0xE7, 0xC3, 0xE7, 0xFF,
0x00, 0x18, 0x24, 0x18, 0x00,
0xFF, 0xE7, 0xDB, 0xE7, 0xFF,
0x30, 0x48, 0x3A, 0x06, 0x0E,
0x26, 0x29, 0x79, 0x29, 0x26,
0x40, 0x7F, 0x05, 0x05, 0x07,
0x40, 0x7F, 0x05, 0x25, 0x3F,
0x5A, 0x3C, 0xE7, 0x3C, 0x5A,
0x7F, 0x3E, 0x1C, 0x1C, 0x08,
0x08, 0x1C, 0x1C, 0x3E, 0x7F,
0x14, 0x22, 0x7F, 0x22, 0x14,
0x5F, 0x5F, 0x00, 0x5F, 0x5F,
0x06, 0x09, 0x7F, 0x01, 0x7F,
0x00, 0x66, 0x89, 0x95, 0x6A,
0x60, 0x60, 0x60, 0x60, 0x60,
0x94, 0xA2, 0xFF, 0xA2, 0x94,
0x08, 0x04, 0x7E, 0x04, 0x08,
0x10, 0x20, 0x7E, 0x20, 0x10,
0x08, 0x08, 0x2A, 0x1C, 0x08,
0x08, 0x1C, 0x2A, 0x08, 0x08,
0x1E, 0x10, 0x10, 0x10, 0x10,
0x0C, 0x1E, 0x0C, 0x1E, 0x0C,
0x30, 0x38, 0x3E, 0x38, 0x30,
0x06, 0x0E, 0x3E, 0x0E, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x5F, 0x00, 0x00,
0x00, 0x07, 0x00, 0x07, 0x00,
0x14, 0x7F, 0x14, 0x7F, 0x14,
0x24, 0x2A, 0x7F, 0x2A, 0x12,
0x23, 0x13, 0x08, 0x64, 0x62,
0x36, 0x49, 0x56, 0x20, 0x50,
0x00, 0x08, 0x07, 0x03, 0x00,
0x00, 0x1C, 0x22, 0x41, 0x00,
0x00, 0x41, 0x22, 0x1C, 0x00,
0x2A, 0x1C, 0x7F, 0x1C, 0x2A,
0x08, 0x08, 0x3E, 0x08, 0x08,
0x00, 0x80, 0x70, 0x30, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x60, 0x60, 0x00,
0x20, 0x10, 0x08, 0x04, 0x02,
0x3E, 0x51, 0x49, 0x45, 0x3E,
0x00, 0x42, 0x7F, 0x40, 0x00,
0x72, 0x49, 0x49, 0x49, 0x46,
0x21, 0x41, 0x49, 0x4D, 0x33,
0x18, 0x14, 0x12, 0x7F, 0x10,
0x27, 0x45, 0x45, 0x45, 0x39,
0x3C, 0x4A, 0x49, 0x49, 0x31,
0x41, 0x21, 0x11, 0x09, 0x07,
0x36, 0x49, 0x49, 0x49, 0x36,
0x46, 0x49, 0x49, 0x29, 0x1E,
0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x40, 0x34, 0x00, 0x00,
0x00, 0x08, 0x14, 0x22, 0x41,
0x14, 0x14, 0x14, 0x14, 0x14,
0x00, 0x41, 0x22, 0x14, 0x08,
0x02, 0x01, 0x59, 0x09, 0x06,
0x3E, 0x41, 0x5D, 0x59, 0x4E,
0x7C, 0x12, 0x11, 0x12, 0x7C,
0x7F, 0x49, 0x49, 0x49, 0x36,
0x3E, 0x41, 0x41, 0x41, 0x22,
0x7F, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x49, 0x49, 0x49, 0x41,
0x7F, 0x09, 0x09, 0x09, 0x01,
0x3E, 0x41, 0x41, 0x51, 0x73,
0x7F, 0x08, 0x08, 0x08, 0x7F,
0x00, 0x41, 0x7F, 0x41, 0x00,
0x20, 0x40, 0x41, 0x3F, 0x01,
0x7F, 0x08, 0x14, 0x22, 0x41,
0x7F, 0x40, 0x40, 0x40, 0x40,
0x7F, 0x02, 0x1C, 0x02, 0x7F,
0x7F, 0x04, 0x08, 0x10, 0x7F,
0x3E, 0x41, 0x41, 0x41, 0x3E,
0x7F, 0x09, 0x09, 0x09, 0x06,
0x3E, 0x41, 0x51, 0x21, 0x5E,
0x7F, 0x09, 0x19, 0x29, 0x46,
0x26, 0x49, 0x49, 0x49, 0x32,
0x03, 0x01, 0x7F, 0x01, 0x03,
0x3F, 0x40, 0x40, 0x40, 0x3F,
0x1F, 0x20, 0x40, 0x20, 0x1F,
0x3F, 0x40, 0x38, 0x40, 0x3F,
0x63, 0x14, 0x08, 0x14, 0x63,
0x03, 0x04, 0x78, 0x04, 0x03,
0x61, 0x59, 0x49, 0x4D, 0x43,
0x00, 0x7F, 0x41, 0x41, 0x41,
0x02, 0x04, 0x08, 0x10, 0x20,
0x00, 0x41, 0x41, 0x41, 0x7F,
0x04, 0x02, 0x01, 0x02, 0x04,
0x40, 0x40, 0x40, 0x40, 0x40,
0x00, 0x03, 0x07, 0x08, 0x00,
0x20, 0x54, 0x54, 0x78, 0x40,
0x7F, 0x28, 0x44, 0x44, 0x38,
0x38, 0x44, 0x44, 0x44, 0x28,
0x38, 0x44, 0x44, 0x28, 0x7F,
0x38, 0x54, 0x54, 0x54, 0x18,
0x00, 0x08, 0x7E, 0x09, 0x02,
0x18, 0xA4, 0xA4, 0x9C, 0x78,
0x7F, 0x08, 0x04, 0x04, 0x78,
0x00, 0x44, 0x7D, 0x40, 0x00,
0x20, 0x40, 0x40, 0x3D, 0x00,
0x7F, 0x10, 0x28, 0x44, 0x00,
0x00, 0x41, 0x7F, 0x40, 0x00,
0x7C, 0x04, 0x78, 0x04, 0x78,
0x7C, 0x08, 0x04, 0x04, 0x78,
0x38, 0x44, 0x44, 0x44, 0x38,
0xFC, 0x18, 0x24, 0x24, 0x18,
0x18, 0x24, 0x24, 0x18, 0xFC,
0x7C, 0x08, 0x04, 0x04, 0x08,
0x48, 0x54, 0x54, 0x54, 0x24,
0x04, 0x04, 0x3F, 0x44, 0x24,
0x3C, 0x40, 0x40, 0x20, 0x7C,
0x1C, 0x20, 0x40, 0x20, 0x1C,
0x3C, 0x40, 0x30, 0x40, 0x3C,
0x44, 0x28, 0x10, 0x28, 0x44,
0x4C, 0x90, 0x90, 0x90, 0x7C,
0x44, 0x64, 0x54, 0x4C, 0x44,
0x00, 0x08, 0x36, 0x41, 0x00,
0x00, 0x00, 0x77, 0x00, 0x00,
0x00, 0x41, 0x36, 0x08, 0x00,
0x02, 0x01, 0x02, 0x04, 0x02,
0x3C, 0x26, 0x23, 0x26, 0x3C,
0x1E, 0xA1, 0xA1, 0x61, 0x12,
0x3A, 0x40, 0x40, 0x20, 0x7A,
0x38, 0x54, 0x54, 0x55, 0x59,
0x21, 0x55, 0x55, 0x79, 0x41,
0x21, 0x54, 0x54, 0x78, 0x41,
0x21, 0x55, 0x54, 0x78, 0x40,
0x20, 0x54, 0x55, 0x79, 0x40,
0x0C, 0x1E, 0x52, 0x72, 0x12,
0x39, 0x55, 0x55, 0x55, 0x59,
0x39, 0x54, 0x54, 0x54, 0x59,
0x39, 0x55, 0x54, 0x54, 0x58,
0x00, 0x00, 0x45, 0x7C, 0x41,
0x00, 0x02, 0x45, 0x7D, 0x42,
0x00, 0x01, 0x45, 0x7C, 0x40,
0xF0, 0x29, 0x24, 0x29, 0xF0,
0xF0, 0x28, 0x25, 0x28, 0xF0,
0x7C, 0x54, 0x55, 0x45, 0x00,
0x20, 0x54, 0x54, 0x7C, 0x54,
0x7C, 0x0A, 0x09, 0x7F, 0x49,
0x32, 0x49, 0x49, 0x49, 0x32,
0x32, 0x48, 0x48, 0x48, 0x32,
0x32, 0x4A, 0x48, 0x48, 0x30,
0x3A, 0x41, 0x41, 0x21, 0x7A,
0x3A, 0x42, 0x40, 0x20, 0x78,
0x00, 0x9D, 0xA0, 0xA0, 0x7D,
0x39, 0x44, 0x44, 0x44, 0x39,
0x3D, 0x40, 0x40, 0x40, 0x3D,
0x3C, 0x24, 0xFF, 0x24, 0x24,
0x48, 0x7E, 0x49, 0x43, 0x66,
0x2B, 0x2F, 0xFC, 0x2F, 0x2B,
0xFF, 0x09, 0x29, 0xF6, 0x20,
0xC0, 0x88, 0x7E, 0x09, 0x03,
0x20, 0x54, 0x54, 0x79, 0x41,
0x00, 0x00, 0x44, 0x7D, 0x41,
0x30, 0x48, 0x48, 0x4A, 0x32,
0x38, 0x40, 0x40, 0x22, 0x7A,
0x00, 0x7A, 0x0A, 0x0A, 0x72,
0x7D, 0x0D, 0x19, 0x31, 0x7D,
0x26, 0x29, 0x29, 0x2F, 0x28,
0x26, 0x29, 0x29, 0x29, 0x26,
0x30, 0x48, 0x4D, 0x40, 0x20,
0x38, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x38,
0x2F, 0x10, 0xC8, 0xAC, 0xBA,
0x2F, 0x10, 0x28, 0x34, 0xFA,
0x00, 0x00, 0x7B, 0x00, 0x00,
0x08, 0x14, 0x2A, 0x14, 0x22,
0x22, 0x14, 0x2A, 0x14, 0x08,
0xAA, 0x00, 0x55, 0x00, 0xAA,
0xAA, 0x55, 0xAA, 0x55, 0xAA,
0x00, 0x00, 0x00, 0xFF, 0x00,
0x10, 0x10, 0x10, 0xFF, 0x00,
0x14, 0x14, 0x14, 0xFF, 0x00,
0x10, 0x10, 0xFF, 0x00, 0xFF,
0x10, 0x10, 0xF0, 0x10, 0xF0,
0x14, 0x14, 0x14, 0xFC, 0x00,
0x14, 0x14, 0xF7, 0x00, 0xFF,
0x00, 0x00, 0xFF, 0x00, 0xFF,
0x14, 0x14, 0xF4, 0x04, 0xFC,
0x14, 0x14, 0x17, 0x10, 0x1F,
0x10, 0x10, 0x1F, 0x10, 0x1F,
0x14, 0x14, 0x14, 0x1F, 0x00,
0x10, 0x10, 0x10, 0xF0, 0x00,
0x00, 0x00, 0x00, 0x1F, 0x10,
0x10, 0x10, 0x10, 0x1F, 0x10,
0x10, 0x10, 0x10, 0xF0, 0x10,
0x00, 0x00, 0x00, 0xFF, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x10, 0xFF, 0x10,
0x00, 0x00, 0x00, 0xFF, 0x14,
0x00, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0x00, 0x1F, 0x10, 0x17,
0x00, 0x00, 0xFC, 0x04, 0xF4,
0x14, 0x14, 0x17, 0x10, 0x17,
0x14, 0x14, 0xF4, 0x04, 0xF4,
0x00, 0x00, 0xFF, 0x00, 0xF7,
0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0xF7, 0x00, 0xF7,
0x14, 0x14, 0x14, 0x17, 0x14,
0x10, 0x10, 0x1F, 0x10, 0x1F,
0x14, 0x14, 0x14, 0xF4, 0x14,
0x10, 0x10, 0xF0, 0x10, 0xF0,
0x00, 0x00, 0x1F, 0x10, 0x1F,
0x00, 0x00, 0x00, 0x1F, 0x14,
0x00, 0x00, 0x00, 0xFC, 0x14,
0x00, 0x00, 0xF0, 0x10, 0xF0,
0x10, 0x10, 0xFF, 0x10, 0xFF,
0x14, 0x14, 0x14, 0xFF, 0x14,
0x10, 0x10, 0x10, 0x1F, 0x00,
0x00, 0x00, 0x00, 0xF0, 0x10,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0xFF, 0xFF, 0xFF, 0x00, 0x00,
0x00, 0x00, 0x00, 0xFF, 0xFF,
0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
0x38, 0x44, 0x44, 0x38, 0x44,
0x7C, 0x2A, 0x2A, 0x3E, 0x14,
0x7E, 0x02, 0x02, 0x06, 0x06,
0x02, 0x7E, 0x02, 0x7E, 0x02,
0x63, 0x55, 0x49, 0x41, 0x63,
0x38, 0x44, 0x44, 0x3C, 0x04,
0x40, 0x7E, 0x20, 0x1E, 0x20,
0x06, 0x02, 0x7E, 0x02, 0x02,
0x99, 0xA5, 0xE7, 0xA5, 0x99,
0x1C, 0x2A, 0x49, 0x2A, 0x1C,
0x4C, 0x72, 0x01, 0x72, 0x4C,
0x30, 0x4A, 0x4D, 0x4D, 0x30,
0x30, 0x48, 0x78, 0x48, 0x30,
0xBC, 0x62, 0x5A, 0x46, 0x3D,
0x3E, 0x49, 0x49, 0x49, 0x00,
0x7E, 0x01, 0x01, 0x01, 0x7E,
0x2A, 0x2A, 0x2A, 0x2A, 0x2A,
0x44, 0x44, 0x5F, 0x44, 0x44,
0x40, 0x51, 0x4A, 0x44, 0x40,
0x40, 0x44, 0x4A, 0x51, 0x40,
0x00, 0x00, 0xFF, 0x01, 0x03,
0xE0, 0x80, 0xFF, 0x00, 0x00,
0x08, 0x08, 0x6B, 0x6B, 0x08,
0x36, 0x12, 0x36, 0x24, 0x36,
0x06, 0x0F, 0x09, 0x0F, 0x06,
0x00, 0x00, 0x18, 0x18, 0x00,
0x00, 0x00, 0x10, 0x10, 0x00,
0x30, 0x40, 0xFF, 0x01, 0x01,
0x00, 0x1F, 0x01, 0x01, 0x1E,
0x00, 0x19, 0x1D, 0x17, 0x12,
0x00, 0x3C, 0x3C, 0x3C, 0x3C,
0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif

View file

@ -1,175 +0,0 @@
// Paint example specifically for the TFTLCD Arduino shield.
// If using the breakout board, use the tftpaint.pde sketch instead!
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include <TouchScreen.h>
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
#ifndef USE_ADAFRUIT_SHIELD_PINOUT
#error "This sketch is intended for use with the TFT LCD Shield. Make sure that USE_ADAFRUIT_SHIELD_PINOUT is #defined in the Adafruit_TFTLCD.h library file."
#endif
// These are the pins for the shield!
#define YP A1 // must be an analog pin, use "An" notation!
#define XM A2 // must be an analog pin, use "An" notation!
#define YM 7 // can be a digital pin
#define XP 6 // can be a digital pin
#ifdef __SAM3X8E__
#define TS_MINX 125
#define TS_MINY 170
#define TS_MAXX 880
#define TS_MAXY 940
#else
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940
#endif
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
Adafruit_TFTLCD tft;
#define BOXSIZE 40
#define PENRADIUS 4
int oldcolor, currentcolor;
void setup(void) {
Serial.begin(9600);
Serial.println(F("Paint!"));
tft.reset();
uint16_t identifier = tft.readID();
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
Serial.println(F("Found ILI9328 LCD driver"));
} else if(identifier == 0x7575) {
Serial.println(F("Found HX8347G LCD driver"));
} else {
Serial.print(F("Unknown LCD driver chip: "));
Serial.println(identifier, HEX);
return;
}
tft.begin(identifier);
tft.fillScreen(BLACK);
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
// tft.fillRect(BOXSIZE*6, 0, BOXSIZE, BOXSIZE, WHITE);
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
currentcolor = RED;
pinMode(13, OUTPUT);
}
#define MINPRESSURE 10
#define MAXPRESSURE 1000
void loop()
{
digitalWrite(13, HIGH);
TSPoint p = ts.getPoint();
digitalWrite(13, LOW);
// if sharing pins, you'll need to fix the directions of the touchscreen pins
//pinMode(XP, OUTPUT);
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
//pinMode(YM, OUTPUT);
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
*/
if (p.y < (TS_MINY-5)) {
Serial.println("erase");
// press the bottom of the screen to erase
tft.fillRect(0, BOXSIZE, tft.width(), tft.height()-BOXSIZE, BLACK);
}
// scale from 0->1023 to tft.width
p.x = map(p.x, TS_MINX, TS_MAXX, tft.width(), 0);
p.y = map(p.y, TS_MINY, TS_MAXY, tft.height(), 0);
/*
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
*/
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
if (oldcolor == GREEN) tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, GREEN);
if (oldcolor == CYAN) tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, CYAN);
if (oldcolor == BLUE) tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, BLUE);
if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}
}

View file

@ -0,0 +1,105 @@
#include <SD.h>
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#define LCD_CS A3 // Chip Select (see notes above)
#define LCD_CD A2 // Command/Data
#define LCD_RD A0 // LCD Read strobe
#define LCD_WR 4 // LCD Write strobe (see notes above)
#define LCD_RESET A4 // Alternately just connect to Arduino's reset pin
#define DMA_SELECT A1 // Hi/lo chooses DMA vs non-DMA effect
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);
#define DMALINES 16
// DMA buffer is 320 pixels * DMALINES * 2 bytes/pixel * 2 buffers
uint8_t dmabuf[320 * DMALINES * 2 * 2];
// Pixel buffer is slightly wider than screen, for X-scrolling
uint16_t pixels[320 + 64];
uint32_t startTime;
void setup()
{
Serial.begin(9600);
while(!Serial);
pinMode(DMA_SELECT, INPUT_PULLUP);
// Initialize pixel buffer with alternating red and white bands,
// 32 pixels wide. 0x00F8 is 16-bit red (0xF800) endian-swapped
// so bytes can be copied directly to screen.
for(int i=0; i<320+64; i++)
pixels[i] = (i & 32) ? 0x00F8 : 0xFFFF;
tft.reset();
uint16_t identifier = tft.readID();
// SEE NOTES ABOVE - this is necessary IF using the
// hard-wired CS (and no inverter) option.
identifier = 0x9341;
if(identifier == 0x9325) {
Serial.println(F("Found ILI9325 LCD driver"));
} else if(identifier == 0x9328) {
Serial.println(F("Found ILI9328 LCD driver"));
} else if(identifier == 0x7575) {
Serial.println(F("Found HX8347G LCD driver"));
} else if(identifier == 0x9341) {
Serial.println(F("Found ILI9341 LCD driver"));
} else if(identifier == 0x8357) {
Serial.println(F("Found HX8357D LCD driver"));
} else {
Serial.print(F("Unknown LCD driver chip: "));
Serial.println(identifier, HEX);
return;
}
tft.begin(identifier);
tft.setRotation(1);
tft.fillScreen(0);
startTime = millis();
}
int lineNum;
int frame = 0;
// pushColorsDMA() callback function -- fills DMALINES scanlines with
// data from pixels[] array.
void myCallback(uint8_t *dest, uint16_t len) {
for(int i=0; i<DMALINES; i++) {
// Wave up to 64 pixels horizontally (extra width in pixels[] array)
int offset = (int)((sin((float)(lineNum + frame) / 40.0) + 1.0) * 31.5);
// Change offset every 32 lines for checkerboard effect
if((lineNum + frame/8) & 32) offset = (offset + 32) % 63;
memcpy(dest, &pixels[offset], len / DMALINES);
lineNum++;
dest += 320 * 2; // Offset to next scanline (2 bytes/pixel)
}
}
void loop() {
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1);
lineNum = 0;
if(digitalRead(DMA_SELECT)) {
tft.pushColorsDMA(tft.width() * tft.height() * 2, dmabuf, tft.width() * DMALINES * 2, myCallback);
} else {
bool first = true;
while(lineNum < tft.height()) {
// Fill the DMA buffer, but don't issue it
myCallback(dmabuf, tft.width() * DMALINES * 2);
// Then send it using non-DMA function:
tft.pushColors((uint16_t *)dmabuf, tft.width() * DMALINES, first);
first = false;
}
}
frame++;
uint32_t elapsed = (millis() - startTime) / 1000;
if(elapsed > 0) {
Serial.print(frame / elapsed);
Serial.println(" fps");
}
}

View file

@ -311,7 +311,6 @@
#define CS_ACTIVE CS_PORT->PIO_CODR |= CS_MASK
#define CS_IDLE CS_PORT->PIO_SODR |= CS_MASK
#else // Due w/Breakout board
#define write8inline(d) { \
@ -326,11 +325,16 @@
RD_IDLE;}
#define setWriteDirInline() { \
PIOC->PIO_MDDR |= 0x000001FE; /*PIOC->PIO_SODR |= 0x000001FE;*/ PIOC->PIO_OER |= 0x000001FE; PIOC->PIO_PER |= 0x000001FE; }
PIOC->PIO_MDDR |= 0x000001FE; \
PIOC->PIO_OER |= 0x000001FE; \
PIOC->PIO_PER |= 0x000001FE; }
#define setReadDirInline() { \
pmc_enable_periph_clk( ID_PIOC ) ; \
PIOC->PIO_PUDR |= 0x000001FE; PIOC->PIO_IFDR |= 0x000001FE; PIOC->PIO_ODR |= 0x000001FE; PIOC->PIO_PER |= 0x000001FE; }
PIOC->PIO_PUDR |= 0x000001FE; \
PIOC->PIO_IFDR |= 0x000001FE; \
PIOC->PIO_ODR |= 0x000001FE; \
PIOC->PIO_PER |= 0x000001FE; }
// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE rdPort->PIO_CODR |= rdPinSet //PIO_Clear(rdPort, rdPinSet)
@ -344,6 +348,41 @@
#endif
#elif defined(__SAMD51__) // Metro / Feather / ItsyBitsy M4
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
// M4 w/shield: TBD
#else // M4 w/breakout
#define write8inline(d) { \
*writePort = d; \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
delayMicroseconds(1); \
result = *readPort; \
RD_IDLE; }
#define setWriteDirInline() { *dirSet = 0xFF; }
#define setReadDirInline() { *dirClr = 0xFF; }
#define RD_ACTIVE *rdPortClr = rdPinMask
#define RD_IDLE *rdPortSet = rdPinMask
/*
#define WR_ACTIVE *wrPortClr = wrPinMask
#define WR_IDLE *wrPortSet = wrPinMask
*/
#define WR_ACTIVE *wrPortSet = wrPinMask
#define WR_IDLE *wrPortClr = wrPinMask
#define CD_COMMAND *cdPortClr = cdPinMask
#define CD_DATA *cdPortSet = cdPinMask
#define CS_ACTIVE *csPortClr = csPinMask
#define CS_IDLE *csPortSet = csPinMask
#endif
#else
@ -351,7 +390,7 @@
#endif
#if !defined(__SAM3X8E__)
#if defined(__AVR__)
// Stuff common to all Arduino AVR board types:
#ifdef USE_ADAFRUIT_SHIELD_PINOUT