32 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
ladyada 8ad1ede59f change init to retry ILI9341 checks a few times 2018-02-22 17:03:41 -05:00
Tony DiCola d73bbf1866 Add GitHub issue template 2016-05-27 13:43:05 -07:00
Tony DiCola 9535fbf889 Add GitHub pull request template 2016-05-27 13:37:54 -07:00
driverblock 97a82854c8 Fixed 3.5" TFT text rotation issue
Fixed MADCTL values for HX8357B
2014-11-13 10:38:59 -05:00
driverblock ecf4cf17b0 add HX8357 driver check 2014-10-31 13:40:29 -04:00
driverblock 6c236e25fa Add HX8357 driver check 2014-10-31 13:39:28 -04:00
ladyada 40266af7ab add HX8357 check 2014-08-15 17:52:54 -04:00
ladyada 6c41da9750 fixes 2014-08-13 18:15:49 -04:00
ladyada 9323b5cdb5 Merge branch 'master' of github.com:adafruit/TFTLCD-Library
Conflicts:
	Adafruit_TFTLCD.cpp
2014-08-13 17:43:31 -04:00
ladyada 87479c7442 Add HX8357D 3.5" tft support 2014-08-13 17:42:46 -04:00
Tony DiCola 7a983dcbc5 Fix #11 by adding SPI.h to tftbmp example. 2014-07-25 18:40:41 -07:00
Tony DiCola 7d70af32ff Update tftbmp example note to mention Arduino mega hardware SPI. 2014-07-22 22:35:12 -07:00
Tony DiCola d9b13dbda0 Fix #12 by sending rotated with/height limits to setAddrWindow instead of hardcoded values. 2014-07-22 16:57:31 -07:00
ladyada 318bb8356e fix for pushcolor 2014-04-30 12:56:09 -04:00
ladyada 162103b583 Merge branch 'master' of github.com:adafruit/TFTLCD-Library 2014-04-30 12:54:08 -04:00
ladyada 879c387a08 added ILI9341 check to tftbmp! 2014-04-30 12:53:37 -04:00
driverblock f775b97d86 Change Point to TSPoint
Someone changed the TouchScreen l;ibrary to define TSPoint instead of Point, but didn't update this example sketch
2014-03-24 17:05:10 -04:00
ladyada 286f81f96e TFTpaint for ili9341 fixed! 2014-03-18 14:35:33 -04:00
ladyada 391f1a503f rotation for ili9341 fixed and also now default 'upright' 2014-03-18 14:33:29 -04:00
ladyada 7fc3d6fb0a fix merge for readreg() and also, add ili9341 to graphicstest 2014-03-18 13:59:34 -04:00
ladyada 6bc43d3e67 Merge branch 'master' of github.com:adafruit/TFTLCD-Library
Conflicts:
	Adafruit_TFTLCD.cpp
	Adafruit_TFTLCD.h
2014-03-17 21:23:22 -04:00
ladyada b9d06458f5 add ILI9341 support - shield is no longer default (new shield has new library) 2014-03-17 21:20:57 -04:00
driverblock 1cf75baa9b Restored
Restored files mistakenly deleted
2013-09-07 17:47:22 -04:00
driverblock 4ccd1148b0 merge follies 2013-09-07 17:44:31 -04:00
driverblock c596e1aa7f Merge branch 'Due' 2013-09-07 17:43:26 -04:00
13 changed files with 1466 additions and 974 deletions
+46
View File
@@ -0,0 +1,46 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**
+26
View File
@@ -0,0 +1,26 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.
+635 -82
View File
@@ -4,83 +4,79 @@
// Graphics library by ladyada/adafruit with init code from Rossum
// MIT license
#if defined(__SAM3X8E__)
#include <include/pio.h>
#define PROGMEM
#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
#define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
#ifdef __AVR__
#include <avr/pgmspace.h>
#include <avr/pgmspace.h>
#endif
#include "pins_arduino.h"
#include "wiring_private.h"
#include "Adafruit_TFTLCD.h"
#include "pin_magic.h"
//#define TFTWIDTH 320
//#define TFTHEIGHT 480
#define TFTWIDTH 240
#define TFTHEIGHT 320
// LCD controller chip identifiers
#define ID_932X 0
#define ID_7575 1
#define ID_9341 2
#define ID_HX8357D 3
#define ID_UNKNOWN 0xFF
// Register names from Peter Barrett's Microtouch code
#define ILI932X_START_OSC 0x00
#define ILI932X_DRIV_OUT_CTRL 0x01
#define ILI932X_DRIV_WAV_CTRL 0x02
#define ILI932X_ENTRY_MOD 0x03
#define ILI932X_RESIZE_CTRL 0x04
#define ILI932X_DISP_CTRL1 0x07
#define ILI932X_DISP_CTRL2 0x08
#define ILI932X_DISP_CTRL3 0x09
#define ILI932X_DISP_CTRL4 0x0A
#define ILI932X_RGB_DISP_IF_CTRL1 0x0C
#define ILI932X_FRM_MARKER_POS 0x0D
#define ILI932X_RGB_DISP_IF_CTRL2 0x0F
#define ILI932X_POW_CTRL1 0x10
#define ILI932X_POW_CTRL2 0x11
#define ILI932X_POW_CTRL3 0x12
#define ILI932X_POW_CTRL4 0x13
#define ILI932X_GRAM_HOR_AD 0x20
#define ILI932X_GRAM_VER_AD 0x21
#define ILI932X_RW_GRAM 0x22
#define ILI932X_POW_CTRL7 0x29
#define ILI932X_FRM_RATE_COL_CTRL 0x2B
#define ILI932X_GAMMA_CTRL1 0x30
#define ILI932X_GAMMA_CTRL2 0x31
#define ILI932X_GAMMA_CTRL3 0x32
#define ILI932X_GAMMA_CTRL4 0x35
#define ILI932X_GAMMA_CTRL5 0x36
#define ILI932X_GAMMA_CTRL6 0x37
#define ILI932X_GAMMA_CTRL7 0x38
#define ILI932X_GAMMA_CTRL8 0x39
#define ILI932X_GAMMA_CTRL9 0x3C
#define ILI932X_GAMMA_CTRL10 0x3D
#define ILI932X_HOR_START_AD 0x50
#define ILI932X_HOR_END_AD 0x51
#define ILI932X_VER_START_AD 0x52
#define ILI932X_VER_END_AD 0x53
#define ILI932X_GATE_SCAN_CTRL1 0x60
#define ILI932X_GATE_SCAN_CTRL2 0x61
#define ILI932X_GATE_SCAN_CTRL3 0x6A
#define ILI932X_PART_IMG1_DISP_POS 0x80
#define ILI932X_PART_IMG1_START_AD 0x81
#define ILI932X_PART_IMG1_END_AD 0x82
#define ILI932X_PART_IMG2_DISP_POS 0x83
#define ILI932X_PART_IMG2_START_AD 0x84
#define ILI932X_PART_IMG2_END_AD 0x85
#define ILI932X_PANEL_IF_CTRL1 0x90
#define ILI932X_PANEL_IF_CTRL2 0x92
#define ILI932X_PANEL_IF_CTRL3 0x93
#define ILI932X_PANEL_IF_CTRL4 0x95
#define ILI932X_PANEL_IF_CTRL5 0x97
#define ILI932X_PANEL_IF_CTRL6 0x98
#include "registers.h"
#define HX8347G_COLADDRSTART_HI 0x02
#define HX8347G_COLADDRSTART_LO 0x03
#define HX8347G_COLADDREND_HI 0x04
#define HX8347G_COLADDREND_LO 0x05
#define HX8347G_ROWADDRSTART_HI 0x06
#define HX8347G_ROWADDRSTART_LO 0x07
#define HX8347G_ROWADDREND_HI 0x08
#define HX8347G_ROWADDREND_LO 0x09
#define HX8347G_MEMACCESS 0x16
#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.
@@ -91,10 +87,41 @@ Adafruit_TFTLCD::Adafruit_TFTLCD(
#ifndef USE_ADAFRUIT_SHIELD_PINOUT
// Convert pin numbers to registers and bitmasks
_reset = reset;
#ifdef __AVR__
csPort = portOutputRegister(digitalPinToPort(cs));
cdPort = portOutputRegister(digitalPinToPort(cd));
wrPort = portOutputRegister(digitalPinToPort(wr));
rdPort = portOutputRegister(digitalPinToPort(rd));
#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);
@@ -103,14 +130,28 @@ Adafruit_TFTLCD::Adafruit_TFTLCD(
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;
#endif
#ifdef __AVR__
*csPort |= csPinSet; // Set all control bits to HIGH (idle)
*cdPort |= cdPinSet; // Signals are ACTIVE LOW
*wrPort |= wrPinSet;
*rdPort |= rdPinSet;
#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);
@@ -205,6 +246,28 @@ static const uint8_t HX8347G_regValues[] PROGMEM = {
0x09 , 0x3F
};
static const uint8_t HX8357D_regValues[] PROGMEM = {
HX8357_SWRESET, 0,
HX8357D_SETC, 3, 0xFF, 0x83, 0x57,
TFTLCD_DELAY, 250,
HX8357_SETRGB, 4, 0x00, 0x00, 0x06, 0x06,
HX8357D_SETCOM, 1, 0x25, // -1.52V
HX8357_SETOSC, 1, 0x68, // Normal mode 70Hz, Idle mode 55 Hz
HX8357_SETPANEL, 1, 0x05, // BGR, Gate direction swapped
HX8357_SETPWR1, 6, 0x00, 0x15, 0x1C, 0x1C, 0x83, 0xAA,
HX8357D_SETSTBA, 6, 0x50, 0x50, 0x01, 0x3C, 0x1E, 0x08,
// MEME GAMMA HERE
HX8357D_SETCYC, 7, 0x02, 0x40, 0x00, 0x2A, 0x2A, 0x0D, 0x78,
HX8357_COLMOD, 1, 0x55,
HX8357_MADCTL, 1, 0xC0,
HX8357_TEON, 1, 0x00,
HX8357_TEARLINE, 2, 0x00, 0x02,
HX8357_SLPOUT, 0,
TFTLCD_DELAY, 150,
HX8357_DISPON, 0,
TFTLCD_DELAY, 50,
};
static const uint16_t ILI932x_regValues[] PROGMEM = {
ILI932X_START_OSC , 0x0001, // Start oscillator
TFTLCD_DELAY , 50, // 50 millisecond delay
@@ -264,6 +327,8 @@ void Adafruit_TFTLCD::begin(uint16_t id) {
reset();
delay(200);
if((id == 0x9325) || (id == 0x9328)) {
uint16_t a, d;
@@ -278,6 +343,60 @@ void Adafruit_TFTLCD::begin(uint16_t id) {
setRotation(rotation);
setAddrWindow(0, 0, TFTWIDTH-1, TFTHEIGHT-1);
} else if (id == 0x9341) {
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;
} else if (id == 0x8357) {
// HX8357D
driver = ID_HX8357D;
CS_ACTIVE;
while(i < sizeof(HX8357D_regValues)) {
uint8_t r = pgm_read_byte(&HX8357D_regValues[i++]);
uint8_t len = pgm_read_byte(&HX8357D_regValues[i++]);
if(r == TFTLCD_DELAY) {
delay(len);
} else {
//Serial.print("Register $"); Serial.print(r, HEX);
//Serial.print(" datalen "); Serial.println(len);
CS_ACTIVE;
CD_COMMAND;
write8(r);
CD_DATA;
for (uint8_t d=0; d<len; d++) {
uint8_t x = pgm_read_byte(&HX8357D_regValues[i++]);
write8(x);
}
CS_IDLE;
}
}
// return;
} else if(id == 0x7575) {
uint8_t a, d;
@@ -294,13 +413,158 @@ 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) {
CS_IDLE;
// CD_DATA;
WR_IDLE;
RD_IDLE;
@@ -328,7 +592,6 @@ void Adafruit_TFTLCD::reset(void) {
// Relevant to rect/screen fills and H/V lines. Input coordinates are
// assumed pre-sorted (e.g. x2 >= x1).
void Adafruit_TFTLCD::setAddrWindow(int x1, int y1, int x2, int y2) {
CS_ACTIVE;
if(driver == ID_932X) {
@@ -388,6 +651,18 @@ void Adafruit_TFTLCD::setAddrWindow(int x1, int y1, int x2, int y2) {
writeRegisterPair(HX8347G_COLADDREND_HI , HX8347G_COLADDREND_LO , x2);
writeRegisterPair(HX8347G_ROWADDREND_HI , HX8347G_ROWADDREND_LO , y2);
} else if ((driver == ID_9341) || (driver == ID_HX8357D)){
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;
}
@@ -415,11 +690,42 @@ void Adafruit_TFTLCD::flood(uint16_t color, uint32_t len) {
CS_ACTIVE;
CD_COMMAND;
if(driver == ID_932X) write8(0x00); // High byte of GRAM register...
write8(0x22); // Write data to GRAM
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;
#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--;
@@ -430,7 +736,7 @@ void Adafruit_TFTLCD::flood(uint16_t color, uint32_t len) {
// on the port(s) and just toggle the write strobe.
while(blocks--) {
i = 16; // 64 pixels/block / 4 pixels/pass
do {
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);
@@ -453,6 +759,11 @@ void Adafruit_TFTLCD::flood(uint16_t color, uint32_t len) {
write8(lo);
}
}
#if defined(__SAMD51__)
}
#endif
CS_IDLE;
}
@@ -556,14 +867,12 @@ void Adafruit_TFTLCD::fillScreen(uint16_t color) {
writeRegister16(0x0020, x);
writeRegister16(0x0021, y);
} else if(driver == ID_7575) {
// For the 7575, there is no settable address pointer, instead the
} else if ((driver == ID_9341) || (driver == ID_7575) || (driver == ID_HX8357D)) {
// 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);
}
@@ -612,7 +921,15 @@ void Adafruit_TFTLCD::drawPixel(int16_t x, int16_t y, uint16_t color) {
hi = color >> 8; lo = color;
CD_COMMAND; write8(0x22); CD_DATA; write8(hi); write8(lo);
} else if ((driver == ID_9341) || (driver == ID_HX8357D)) {
setAddrWindow(x, y, _width-1, _height-1);
CS_ACTIVE;
CD_COMMAND;
write8(0x2C);
CD_DATA;
write8(color >> 8); write8(color);
}
CS_IDLE;
}
@@ -620,16 +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);
write8(0x22);
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;
#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
@@ -637,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;
}
@@ -660,7 +1071,8 @@ void Adafruit_TFTLCD::setRotation(uint8_t x) {
// For 932X, init default full-screen address window:
setAddrWindow(0, 0, _width - 1, _height - 1); // CS_IDLE happens here
} if(driver == ID_7575) {
}
if(driver == ID_7575) {
uint8_t t;
switch(rotation) {
@@ -674,9 +1086,53 @@ void Adafruit_TFTLCD::setRotation(uint8_t x) {
// drawPixel() cheats by setting only the top left...by default,
// the lower right is always reset to the corner.
setLR(); // CS_IDLE happens here
}
}
if (driver == ID_9341) {
// MEME, HX8357D uses same registers as 9341 but different values
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
}
if (driver == ID_HX8357D) {
// MEME, HX8357D uses same registers as 9341 but different values
uint16_t t;
switch (rotation) {
case 2:
t = HX8357B_MADCTL_RGB;
break;
case 3:
t = HX8357B_MADCTL_MX | HX8357B_MADCTL_MV | HX8357B_MADCTL_RGB;
break;
case 0:
t = HX8357B_MADCTL_MX | HX8357B_MADCTL_MY | HX8357B_MADCTL_RGB;
break;
case 1:
t = HX8357B_MADCTL_MY | HX8357B_MADCTL_MV | HX8357B_MADCTL_RGB;
break;
}
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()
@@ -751,9 +1207,42 @@ uint16_t Adafruit_TFTLCD::readPixel(int16_t x, int16_t y) {
// Ditto with the read/write port directions, as above.
uint16_t Adafruit_TFTLCD::readID(void) {
uint16_t id;
// retry a bunch!
for (int i = 0; i<5; i++) {
id = readReg(0xD3);
if (id == 0x9341) {
return id;
}
}
uint8_t hi, lo;
/*
for (uint8_t i=0; i<128; i++) {
Serial.print("$"); Serial.print(i, HEX);
Serial.print(" = 0x"); Serial.println(readReg(i), HEX);
}
*/
if (readReg(0x04) == 0x8000) { // eh close enough
// setc!
/*
Serial.println("!");
for (uint8_t i=0; i<254; i++) {
Serial.print("$"); Serial.print(i, HEX);
Serial.print(" = 0x"); Serial.println(readReg(i), HEX);
}
*/
writeRegister24(HX8357D_SETC, 0xFF8357);
delay(300);
//Serial.println(readReg(0xD0), HEX);
if (readReg(0xD0) == 0x990000) {
return 0x8357;
}
}
CS_ACTIVE;
CD_COMMAND;
write8(0x00);
@@ -765,7 +1254,38 @@ uint16_t Adafruit_TFTLCD::readID(void) {
setWriteDir(); // Restore LCD data port(s) to WRITE configuration
CS_IDLE;
return (hi << 8) | lo;
id = hi; id <<= 8; id |= lo;
return id;
}
uint32_t Adafruit_TFTLCD::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
//Serial.print("Read $"); Serial.print(r, HEX);
//Serial.print(":\t0x"); Serial.println(id, HEX);
return id;
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
@@ -820,3 +1340,36 @@ void Adafruit_TFTLCD::writeRegisterPair(uint8_t aH, uint8_t aL, uint16_t d) {
}
#endif
void Adafruit_TFTLCD::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_TFTLCD::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;
}
+48 -18
View File
@@ -11,11 +11,13 @@
#else
#include "WProgram.h"
#endif
#include <Adafruit_GFX.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
//#define USE_ADAFRUIT_SHIELD_PINOUT 1
class Adafruit_TFTLCD : public Adafruit_GFX {
@@ -24,23 +26,31 @@ class Adafruit_TFTLCD : public Adafruit_GFX {
Adafruit_TFTLCD(uint8_t cs, uint8_t cd, uint8_t wr, uint8_t rd, uint8_t rst);
Adafruit_TFTLCD(void);
void begin(uint16_t id = 0x9325),
drawPixel(int16_t x, int16_t y, uint16_t color),
drawFastHLine(int16_t x0, int16_t y0, int16_t w, uint16_t color),
drawFastVLine(int16_t x0, int16_t y0, int16_t h, uint16_t color),
fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t c),
fillScreen(uint16_t color),
reset(void),
setRegisters8(uint8_t *ptr, uint8_t n),
setRegisters16(uint16_t *ptr, uint8_t n),
setRotation(uint8_t x),
// These methods are public in order for BMP examples to work:
setAddrWindow(int x1, int y1, int x2, int y2),
pushColors(uint16_t *data, uint8_t len, boolean first);
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);
#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),
readID(void);
uint32_t readReg(uint8_t r);
private:
@@ -62,21 +72,41 @@ class Adafruit_TFTLCD : public Adafruit_GFX {
#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
volatile uint8_t *csPort , *cdPort , *wrPort , *rdPort;
uint8_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
csPinUnset, cdPinUnset, wrPinUnset, rdPinUnset,
_reset;
#ifdef __AVR__
volatile uint8_t *csPort , *cdPort , *wrPort , *rdPort;
uint8_t csPinSet , cdPinSet , wrPinSet , rdPinSet ,
csPinUnset, cdPinUnset, wrPinUnset, rdPinUnset,
_reset;
#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
};
+61 -30
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,30 +46,36 @@
#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
Serial.print("TFT size is "); Serial.print(tft.width()); Serial.print("x"); Serial.println(tft.height());
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);
@@ -72,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 "));
@@ -377,4 +409,3 @@ unsigned long testFilledRoundRects() {
return micros() - start;
}
-219
View File
@@ -1,219 +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 {
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);
}
}
+229 -53
View File
@@ -1,58 +1,86 @@
// 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 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>
// 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) {
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);
@@ -66,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!"));
bmpDraw("woof.bmp", 0, 0);
delay(1000);
Serial.println(F("OK!"));
tft.fillScreen(0x001F);
if(digitalRead(DMA_SELECT))
bmpDrawDMA("woof.bmp", 0, 0);
else
bmpDraw("woof.bmp", 0, 0);
// delay(1000);
}
void loop()
@@ -84,12 +119,39 @@ void loop()
tft.setRotation(i);
tft.fillScreen(0);
for(int j=0; j <= 200; j += 50) {
bmpDraw("miniwoof.bmp", j, j);
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
@@ -98,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)
@@ -117,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;
@@ -203,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
@@ -216,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);
}
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;
}
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;
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."));
}
-225
View File
@@ -1,225 +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, make sure the SD library is configured for
// 'soft' SPI in the file Sd2Card.h.
#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 {
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;
}
-174
View File
@@ -1,174 +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>
// 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 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 {
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);
Point 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);
}
}
}
@@ -1,163 +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>
#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
#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
// 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);
Point 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);
}
}
}
+105
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");
}
}
+144 -10
View File
@@ -32,11 +32,12 @@
// given for each supported board.
// Shield pin usage:
// LCD Data Bit : 7 6 5 4 3 2 1 0
// Digital pin #: 7 6 13 4 11 10 9 8
// Uno port/pin : PD7 PD6 PB5 PD4 PB3 PB2 PB1 PB0
// Mega port/pin: PH4 PH3 PB7 PG5 PB5 PB4 PH6 PH5
// Leo port/pin : PE6 PD7 PC7 PD4 PB7 PB6 PB5 PB4
// LCD Data Bit : 7 6 5 4 3 2 1 0
// Digital pin #: 7 6 13 4 11 10 9 8
// Uno port/pin : PD7 PD6 PB5 PD4 PB3 PB2 PB1 PB0
// Mega port/pin: PH4 PH3 PB7 PG5 PB5 PB4 PH6 PH5
// Leo port/pin : PE6 PD7 PC7 PD4 PB7 PB6 PB5 PB4
// Due port/pin : PC23 PC24 PB27 PC26 PD7 PC29 PC21 PC22
// 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
@@ -45,6 +46,8 @@
// Mega port/pin: PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 (one contiguous PORT)
// Leo dig. pin : 7 6 5 4 3 2 9 8
// Leo port/pin : PE6 PD7 PC6 PD4 PD0 PD1 PB5 PB4
// Due dig. pin : 40 39 38 37 36 35 34 33
// Due port/pin : PC8 PC7 PC6 PC5 PC4 PC3 PC2 PC1 (one contiguous PORT. -ish…)
// 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.
@@ -67,10 +70,10 @@
// LCD control lines:
// RD (read), WR (write), CD (command/data), CS (chip select)
#define RD_PORT PORTC
#define WR_PORT PORTC
#define CD_PORT PORTC
#define CS_PORT PORTC
#define RD_PORT PORTC /*pin A0 */
#define WR_PORT PORTC /*pin A1 */
#define CD_PORT PORTC /*pin A2 */
#define CS_PORT PORTC /*pin A3 */
#define RD_MASK B00000001
#define WR_MASK B00000010
#define CD_MASK B00000100
@@ -252,13 +255,143 @@
// program to compile.
#define write8 write8inline
#elif defined(__SAM3X8E__)
// Arduino Due
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
#define RD_PORT PIOA /*pin A0 */
#define WR_PORT PIOA /*pin A1 */
#define CD_PORT PIOA /*pin A2 */
#define CS_PORT PIOA /*pin A3 */
#define RD_MASK 0x00010000
#define WR_MASK 0x01000000
#define CD_MASK 0x00800000
#define CS_MASK 0x00400000
#define write8inline(d) { \
PIO_Set(PIOD, (((d) & 0x08)<<(7-3))); \
PIO_Clear(PIOD, (((~d) & 0x08)<<(7-3))); \
PIO_Set(PIOC, (((d) & 0x01)<<(22-0)) | (((d) & 0x02)<<(21-1))| (((d) & 0x04)<<(29-2))| (((d) & 0x10)<<(26-4))| (((d) & 0x40)<<(24-6))| (((d) & 0x80)<<(23-7))); \
PIO_Clear(PIOC, (((~d) & 0x01)<<(22-0)) | (((~d) & 0x02)<<(21-1))| (((~d) & 0x04)<<(29-2))| (((~d) & 0x10)<<(26-4))| (((~d) & 0x40)<<(24-6))| (((~d) & 0x80)<<(23-7))); \
PIO_Set(PIOB, (((d) & 0x20)<<(27-5))); \
PIO_Clear(PIOB, (((~d) & 0x20)<<(27-5))); \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
delayMicroseconds(1); \
result = (((PIOC->PIO_PDSR & (1<<23)) >> (23-7)) | ((PIOC->PIO_PDSR & (1<<24)) >> (24-6)) | \
((PIOB->PIO_PDSR & (1<<27)) >> (27-5)) | ((PIOC->PIO_PDSR & (1<<26)) >> (26-4)) | \
((PIOD->PIO_PDSR & (1<< 7)) >> ( 7-3)) | ((PIOC->PIO_PDSR & (1<<29)) >> (29-2)) | \
((PIOC->PIO_PDSR & (1<<21)) >> (21-1)) | ((PIOC->PIO_PDSR & (1<<22)) >> (22-0))); \
RD_IDLE;}
#define setWriteDirInline() { \
PIOD->PIO_MDDR |= 0x00000080; /*PIOD->PIO_SODR = 0x00000080;*/ PIOD->PIO_OER |= 0x00000080; PIOD->PIO_PER |= 0x00000080; \
PIOC->PIO_MDDR |= 0x25E00000; /*PIOC->PIO_SODR = 0x25E00000;*/ PIOC->PIO_OER |= 0x25E00000; PIOC->PIO_PER |= 0x25E00000; \
PIOB->PIO_MDDR |= 0x08000000; /*PIOB->PIO_SODR = 0x08000000;*/ PIOB->PIO_OER |= 0x08000000; PIOB->PIO_PER |= 0x08000000; }
#define setReadDirInline() { \
pmc_enable_periph_clk(ID_PIOD); pmc_enable_periph_clk(ID_PIOC); pmc_enable_periph_clk(ID_PIOB) ; \
PI OD->PIO_PUDR |= 0x00000080; PIOD->PIO_IFDR |= 0x00000080; PIOD->PIO_ODR |= 0x00000080; PIOD->PIO_PER |= 0x00000080; \
PIOC->PIO_PUDR |= 0x25E00000; PIOC->PIO_IFDR |= 0x25E00000; PIOC->PIO_ODR |= 0x25E00000; PIOC->PIO_PER |= 0x25E00000; \
PIOB->PIO_PUDR |= 0x08000000; PIOB->PIO_IFDR |= 0x08000000; PIOB->PIO_ODR |= 0x08000000; PIOB->PIO_PER |= 0x08000000; }
// Control signals are ACTIVE LOW (idle is HIGH)
// Command/Data: LOW = command, HIGH = data
// These are single-instruction operations and always inline
#define RD_ACTIVE RD_PORT->PIO_CODR |= RD_MASK
#define RD_IDLE RD_PORT->PIO_SODR |= RD_MASK
#define WR_ACTIVE WR_PORT->PIO_CODR |= WR_MASK
#define WR_IDLE WR_PORT->PIO_SODR |= WR_MASK
#define CD_COMMAND CD_PORT->PIO_CODR |= CD_MASK
#define CD_DATA CD_PORT->PIO_SODR |= CD_MASK
#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) { \
PIO_Set(PIOC, (((d) & 0xFF)<<1)); \
PIO_Clear(PIOC, (((~d) & 0xFF)<<1)); \
WR_STROBE; }
#define read8inline(result) { \
RD_ACTIVE; \
delayMicroseconds(1); \
result = ((PIOC->PIO_PDSR & 0x1FE) >> 1); \
RD_IDLE;}
#define setWriteDirInline() { \
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; }
// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE rdPort->PIO_CODR |= rdPinSet //PIO_Clear(rdPort, rdPinSet)
#define RD_IDLE rdPort->PIO_SODR |= rdPinSet //PIO_Set(rdPort, rdPinSet)
#define WR_ACTIVE wrPort->PIO_CODR |= wrPinSet //PIO_Clear(wrPort, wrPinSet)
#define WR_IDLE wrPort->PIO_SODR |= wrPinSet //PIO_Set(wrPort, wrPinSet)
#define CD_COMMAND cdPort->PIO_CODR |= cdPinSet //PIO_Clear(cdPort, cdPinSet)
#define CD_DATA cdPort->PIO_SODR |= cdPinSet //PIO_Set(cdPort, cdPinSet)
#define CS_ACTIVE csPort->PIO_CODR |= csPinSet //PIO_Clear(csPort, csPinSet)
#define CS_IDLE csPort->PIO_SODR |= csPinSet //PIO_Set(csPort, csPinSet)
#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
#error "Board type unsupported / not recognized"
#endif
// Stuff common to all Arduino board types:
#if defined(__AVR__)
// Stuff common to all Arduino AVR board types:
#ifdef USE_ADAFRUIT_SHIELD_PINOUT
@@ -287,6 +420,7 @@
#define CS_IDLE *csPort |= csPinSet
#endif
#endif
// Data write strobe, ~2 instructions and always inline
#define WR_STROBE { WR_ACTIVE; WR_IDLE; }
+172
View File
@@ -0,0 +1,172 @@
// Register names from Peter Barrett's Microtouch code
#define ILI932X_START_OSC 0x00
#define ILI932X_DRIV_OUT_CTRL 0x01
#define ILI932X_DRIV_WAV_CTRL 0x02
#define ILI932X_ENTRY_MOD 0x03
#define ILI932X_RESIZE_CTRL 0x04
#define ILI932X_DISP_CTRL1 0x07
#define ILI932X_DISP_CTRL2 0x08
#define ILI932X_DISP_CTRL3 0x09
#define ILI932X_DISP_CTRL4 0x0A
#define ILI932X_RGB_DISP_IF_CTRL1 0x0C
#define ILI932X_FRM_MARKER_POS 0x0D
#define ILI932X_RGB_DISP_IF_CTRL2 0x0F
#define ILI932X_POW_CTRL1 0x10
#define ILI932X_POW_CTRL2 0x11
#define ILI932X_POW_CTRL3 0x12
#define ILI932X_POW_CTRL4 0x13
#define ILI932X_GRAM_HOR_AD 0x20
#define ILI932X_GRAM_VER_AD 0x21
#define ILI932X_RW_GRAM 0x22
#define ILI932X_POW_CTRL7 0x29
#define ILI932X_FRM_RATE_COL_CTRL 0x2B
#define ILI932X_GAMMA_CTRL1 0x30
#define ILI932X_GAMMA_CTRL2 0x31
#define ILI932X_GAMMA_CTRL3 0x32
#define ILI932X_GAMMA_CTRL4 0x35
#define ILI932X_GAMMA_CTRL5 0x36
#define ILI932X_GAMMA_CTRL6 0x37
#define ILI932X_GAMMA_CTRL7 0x38
#define ILI932X_GAMMA_CTRL8 0x39
#define ILI932X_GAMMA_CTRL9 0x3C
#define ILI932X_GAMMA_CTRL10 0x3D
#define ILI932X_HOR_START_AD 0x50
#define ILI932X_HOR_END_AD 0x51
#define ILI932X_VER_START_AD 0x52
#define ILI932X_VER_END_AD 0x53
#define ILI932X_GATE_SCAN_CTRL1 0x60
#define ILI932X_GATE_SCAN_CTRL2 0x61
#define ILI932X_GATE_SCAN_CTRL3 0x6A
#define ILI932X_PART_IMG1_DISP_POS 0x80
#define ILI932X_PART_IMG1_START_AD 0x81
#define ILI932X_PART_IMG1_END_AD 0x82
#define ILI932X_PART_IMG2_DISP_POS 0x83
#define ILI932X_PART_IMG2_START_AD 0x84
#define ILI932X_PART_IMG2_END_AD 0x85
#define ILI932X_PANEL_IF_CTRL1 0x90
#define ILI932X_PANEL_IF_CTRL2 0x92
#define ILI932X_PANEL_IF_CTRL3 0x93
#define ILI932X_PANEL_IF_CTRL4 0x95
#define ILI932X_PANEL_IF_CTRL5 0x97
#define ILI932X_PANEL_IF_CTRL6 0x98
#define HX8347G_COLADDRSTART_HI 0x02
#define HX8347G_COLADDRSTART_LO 0x03
#define HX8347G_COLADDREND_HI 0x04
#define HX8347G_COLADDREND_LO 0x05
#define HX8347G_ROWADDRSTART_HI 0x06
#define HX8347G_ROWADDRSTART_LO 0x07
#define HX8347G_ROWADDREND_HI 0x08
#define HX8347G_ROWADDREND_LO 0x09
#define HX8347G_MEMACCESS 0x16
#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_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_MEMCONTROL 0x36
#define ILI9341_MADCTL 0x36
#define ILI9341_MADCTL_MY 0x80
#define ILI9341_MADCTL_MX 0x40
#define ILI9341_MADCTL_MV 0x20
#define ILI9341_MADCTL_ML 0x10
#define ILI9341_MADCTL_RGB 0x00
#define ILI9341_MADCTL_BGR 0x08
#define ILI9341_MADCTL_MH 0x04
#define HX8357_NOP 0x00
#define HX8357_SWRESET 0x01
#define HX8357_RDDID 0x04
#define HX8357_RDDST 0x09
#define HX8357B_RDPOWMODE 0x0A
#define HX8357B_RDMADCTL 0x0B
#define HX8357B_RDCOLMOD 0x0C
#define HX8357B_RDDIM 0x0D
#define HX8357B_RDDSDR 0x0F
#define HX8357_SLPIN 0x10
#define HX8357_SLPOUT 0x11
#define HX8357B_PTLON 0x12
#define HX8357B_NORON 0x13
#define HX8357_INVOFF 0x20
#define HX8357_INVON 0x21
#define HX8357_DISPOFF 0x28
#define HX8357_DISPON 0x29
#define HX8357_CASET 0x2A
#define HX8357_PASET 0x2B
#define HX8357_RAMWR 0x2C
#define HX8357_RAMRD 0x2E
#define HX8357B_PTLAR 0x30
#define HX8357_TEON 0x35
#define HX8357_TEARLINE 0x44
#define HX8357_MADCTL 0x36
#define HX8357_COLMOD 0x3A
#define HX8357_SETOSC 0xB0
#define HX8357_SETPWR1 0xB1
#define HX8357B_SETDISPLAY 0xB2
#define HX8357_SETRGB 0xB3
#define HX8357D_SETCOM 0xB6
#define HX8357B_SETDISPMODE 0xB4
#define HX8357D_SETCYC 0xB4
#define HX8357B_SETOTP 0xB7
#define HX8357D_SETC 0xB9
#define HX8357B_SET_PANEL_DRIVING 0xC0
#define HX8357D_SETSTBA 0xC0
#define HX8357B_SETDGC 0xC1
#define HX8357B_SETID 0xC3
#define HX8357B_SETDDB 0xC4
#define HX8357B_SETDISPLAYFRAME 0xC5
#define HX8357B_GAMMASET 0xC8
#define HX8357B_SETCABC 0xC9
#define HX8357_SETPANEL 0xCC
#define HX8357B_SETPOWER 0xD0
#define HX8357B_SETVCOM 0xD1
#define HX8357B_SETPWRNORMAL 0xD2
#define HX8357B_RDID1 0xDA
#define HX8357B_RDID2 0xDB
#define HX8357B_RDID3 0xDC
#define HX8357B_RDID4 0xDD
#define HX8357D_SETGAMMA 0xE0
#define HX8357B_SETGAMMA 0xC8
#define HX8357B_SETPANELRELATED 0xE9
#define HX8357B_MADCTL_MY 0x80
#define HX8357B_MADCTL_MX 0x40
#define HX8357B_MADCTL_MV 0x20
#define HX8357B_MADCTL_ML 0x10
#define HX8357B_MADCTL_RGB 0x00
#define HX8357B_MADCTL_BGR 0x08
#define HX8357B_MADCTL_MH 0x04