Remove some temp files, oops

This commit is contained in:
Phillip Burgess 2018-12-10 14:58:47 -08:00
parent 7b04012eaf
commit b74f3bf681
5 changed files with 0 additions and 2031 deletions

View File

@ -1,831 +0,0 @@
/*!
* @file Adafruit_SPITFT.cpp
*
* @mainpage Adafruit SPI TFT Displays
*
* @section intro_sec Introduction
This is our library for generic SPI TFT Displays with
address windows and 16 bit color (e.g. ILI9341, HX8357D, ST7735...)
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
* @section dependencies Dependencies
*
* This library depends on <a href="https://github.com/adafruit/Adafruit_GFX">
* Adafruit_GFX</a> being present on your system. Please make sure you have
* installed the latest version before using this library.
*
* @section author Author
*
* Written by Limor "ladyada" Fried for Adafruit Industries.
*
* @section license License
*
* BSD license, all text here must be included in any redistribution.
*
*/
#if !defined(__AVR_ATtiny85__) // NOT A CHANCE of this stuff working on ATtiny
#include "Adafruit_SPITFT.h"
#if !defined(ARDUINO_STM32_FEATHER)
#include "pins_arduino.h"
#endif
#if !defined(ARDUINO_STM32_FEATHER) && !defined(RASPI)
#include "wiring_private.h"
#endif
#include <limits.h>
//elif defined(__SAMD21G18A__) || defined(__SAMD21J18A__) || defined(__SAMD21E17A__) || defined(__SAMD21E18A__)
#ifdef ARDUINO_ARCH_SAMD && !defined(__SAMD51__)
// On SAMD21, redefine digitalPinToPort() to use the slightly-faster
// PORT_IOBUS rather than PORT (not needed on SAMD51).
#undef digitalPinToPort
#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort]))
#endif
#include "Adafruit_SPITFT_Macros.h"
#ifdef USE_SPI_DMA
#include <Adafruit_ZeroDMA.h>
#include <malloc.h> // memalign() function
// DMA transfer-in-progress indicator and callback
static volatile boolean dma_busy = false;
static volatile Adafruit_SPITFT *spitft = NULL;
static void dma_callback(Adafruit_ZeroDMA *dma) {
// If spitft pointer is set, deselect TFT and end the SPI transaction
// here in the callback rather than at end of drawing function. Avoids
// a (possibly unnecessary) function call at the start of every graphics
// operation. Can't do this in SPI_BEGIN_TRANSACTION because other code
// outside the library (e.g. SD card reading) may be waiting on the
// GFX SPI transaction to end first.
if(spitft) {
((Adafruit_SPITFT *)spitft)->endWrite();
spitft = NULL;
}
dma_busy = false;
}
/**************************************************************************/
/*!
@brief Poll whether a previous DMA operation is still in-progress.
@return true if SPITFT DMA operation in progress, false if available.
*/
/**************************************************************************/
boolean Adafruit_SPITFT::DMA_busy(void) {
return dma_busy;
}
#define DMA_WAIT while(dma_busy); ///< Wait for dma busy flag to clear
#else
#define DMA_WAIT ///< Do nothing; DMA not used
#endif // USE_SPI_DMA
/**************************************************************************/
/*!
@brief Pass 8-bit (each) R,G,B, get back 16-bit packed color
This function converts 8-8-8 RGB data to 16-bit 5-6-5
@param red Red 8 bit color
@param green Green 8 bit color
@param blue Blue 8 bit color
@return Unsigned 16-bit down-sampled color in 5-6-5 format
*/
/**************************************************************************/
uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) {
return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3);
}
/**************************************************************************/
/*!
@brief Instantiate Adafruit SPI display driver with software SPI
@param w Display width in pixels
@param h Display height in pixels
@param cs Chip select pin #
@param dc Data/Command pin #
@param mosi SPI MOSI pin #
@param sclk SPI Clock pin #
@param rst Reset pin # (optional, pass -1 if unused)
@param miso SPI MISO pin # (optional, pass -1 if unused)
*/
/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h,
int8_t cs, int8_t dc, int8_t mosi,
int8_t sclk, int8_t rst, int8_t miso)
: Adafruit_GFX(w, h) {
_cs = cs;
_dc = dc;
_rst = rst;
_sclk = sclk;
_mosi = mosi;
_miso = miso;
_freq = 0;
#ifdef USE_FAST_PINIO
dcport = (RwReg *)portOutputRegister(digitalPinToPort(dc));
dcpinmask = digitalPinToBitMask(dc);
clkport = (RwReg *)portOutputRegister(digitalPinToPort(sclk));
clkpinmask = digitalPinToBitMask(sclk);
mosiport = (RwReg *)portOutputRegister(digitalPinToPort(mosi));
mosipinmask = digitalPinToBitMask(mosi);
if(miso >= 0){
misoport = (RwReg *)portInputRegister(digitalPinToPort(miso));
misopinmask = digitalPinToBitMask(miso);
} else {
misoport = 0;
misopinmask = 0;
}
if(cs >= 0) {
csport = (RwReg *)portOutputRegister(digitalPinToPort(cs));
cspinmask = digitalPinToBitMask(cs);
} else {
// No chip-select line defined; might be permanently tied to GND.
// Assign a valid GPIO register (though not used for CS), and an
// empty pin bitmask...the nonsense bit-twiddling might be faster
// than checking _cs and possibly branching.
csport = dcport;
cspinmask = 0;
}
#endif
}
/**************************************************************************/
/*!
@brief Instantiate Adafruit SPI display driver with hardware SPI
@param w Display width in pixels
@param h Display height in pixels
@param cs Chip select pin #
@param dc Data/Command pin #
@param rst Reset pin # (optional, pass -1 if unused)
*/
/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h,
int8_t cs, int8_t dc, int8_t rst)
: Adafruit_SPITFT(w, h, &SPI, cs, dc, rst)
{
// We just call the hardware SPI instantiator with the default SPI device (&SPI)
}
/**************************************************************************/
/*!
@brief Instantiate Adafruit SPI display driver with hardware SPI
@param w Display width in pixels
@param h Display height in pixels
@param spiClass A pointer to an SPI hardware interface, e.g. &SPI1
@param cs Chip select pin #
@param dc Data/Command pin #
@param rst Reset pin # (optional, pass -1 if unused)
*/
/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass,
int8_t cs, int8_t dc, int8_t rst)
: Adafruit_GFX(w, h) {
_cs = cs;
_dc = dc;
_rst = rst;
_spi = spiClass;
_sclk = -1;
_mosi = -1;
_miso = -1;
_freq = 0;
#ifdef USE_FAST_PINIO
clkport = 0;
clkpinmask = 0;
mosiport = 0;
mosipinmask = 0;
misoport = 0;
misopinmask = 0;
dcport = (RwReg *)portOutputRegister(digitalPinToPort(dc));
dcpinmask = digitalPinToBitMask(dc);
if(cs >= 0) {
csport = (RwReg *)portOutputRegister(digitalPinToPort(cs));
cspinmask = digitalPinToBitMask(cs);
} else {
// See notes in prior constructor.
csport = dcport;
cspinmask = 0;
}
#endif
}
/**************************************************************************/
/*!
@brief Initialiaze the SPI interface (hardware or software)
@param freq The desired maximum SPI hardware clock frequency
*/
/**************************************************************************/
void Adafruit_SPITFT::initSPI(uint32_t freq) {
_freq = freq;
// Control Pins
if(_cs >= 0) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH); // Deselect
}
pinMode(_dc, OUTPUT);
digitalWrite(_dc, LOW);
// Software SPI
if(_sclk >= 0){
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, LOW);
pinMode(_sclk, OUTPUT);
digitalWrite(_sclk, HIGH);
if(_miso >= 0){
pinMode(_miso, INPUT);
}
}
// Hardware SPI
SPI_BEGIN();
// toggle RST low to reset
if (_rst >= 0) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
digitalWrite(_rst, LOW);
delay(100);
digitalWrite(_rst, HIGH);
delay(200);
}
#ifdef USE_SPI_DMA
// INITIALIZE DMA
if(dma.allocate() == DMA_STATUS_OK) { // Allocate channel
// The DMA library needs to allocate at least one valid descriptor,
// so we do that here. It's not used in the conventional sense though,
// just before a transfer we copy descriptor[0] to this address.
if(dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE,
false, false)) {
// Determine maximum number of descriptors required based on
// total display pixels. Maximum of 32,767 (not 32,768) pixels
// per DMA descriptor (because 2 bytes/pixel, and max 65,535
// (not 65,536) bytes/DMA desc). Round up for last descriptor.
int numDescriptors =
(WIDTH * HEIGHT + DMA_PIXELS - 1) / DMA_PIXELS;
// DMA descriptors MUST be 128-bit (16 byte) aligned.
// memalign() is considered 'obsolete' but it's replacements
// (aligned_alloc() or posix_memalign()) are not currently
// available in the version of ARM GCC in use, but this is,
// so here we are.
if((descriptor = (DmacDescriptor *)memalign(16,
numDescriptors * sizeof(DmacDescriptor)))) {
// Set up SPI DMA on SAMD boards:
int dmac_id;
volatile uint32_t *data_reg;
Serial.println("_spi: ");
Serial.println((uint32_t)_spi);
Serial.println("&SPI: ");
Serial.println((uint32_t)&SPI);
Serial.println("&SPI1: ");
Serial.println((uint32_t)&SPI1);
if(&PERIPH_SPI == &sercom0) {
dmac_id = SERCOM0_DMAC_ID_TX;
data_reg = &SERCOM0->SPI.DATA.reg;
#if defined SERCOM1
} else if(&PERIPH_SPI == &sercom1) {
dmac_id = SERCOM1_DMAC_ID_TX;
data_reg = &SERCOM1->SPI.DATA.reg;
#endif
#if defined SERCOM2
} else if(&PERIPH_SPI == &sercom2) {
dmac_id = SERCOM2_DMAC_ID_TX;
data_reg = &SERCOM2->SPI.DATA.reg;
#endif
#if defined SERCOM3
} else if(&PERIPH_SPI == &sercom3) {
dmac_id = SERCOM3_DMAC_ID_TX;
data_reg = &SERCOM3->SPI.DATA.reg;
#endif
#if defined SERCOM4
} else if(&PERIPH_SPI == &sercom4) {
dmac_id = SERCOM4_DMAC_ID_TX;
data_reg = &SERCOM4->SPI.DATA.reg;
#endif
#if defined SERCOM5
} else if(&PERIPH_SPI == &sercom5) {
dmac_id = SERCOM5_DMAC_ID_TX;
data_reg = &SERCOM5->SPI.DATA.reg;
#endif
}
dma.setTrigger(dmac_id);
dma.setAction(DMA_TRIGGER_ACTON_BEAT);
// Initialize descriptor list.
for(int d=0; d<numDescriptors; d++) {
// No need to set SRCADDR, DESCADDR or BTCNT --
// those are done in the pixel-writing functions.
descriptor[d].BTCTRL.bit.VALID = true;
descriptor[d].BTCTRL.bit.EVOSEL =
DMA_EVENT_OUTPUT_DISABLE;
descriptor[d].BTCTRL.bit.BLOCKACT =
DMA_BLOCK_ACTION_NOACT;
descriptor[d].BTCTRL.bit.BEATSIZE = DMA_BEAT_SIZE_BYTE;
descriptor[d].BTCTRL.bit.DSTINC = 0;
descriptor[d].BTCTRL.bit.STEPSEL = DMA_STEPSEL_SRC;
descriptor[d].BTCTRL.bit.STEPSIZE =
DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
descriptor[d].DSTADDR.reg = (uint32_t)data_reg;
}
// MAKE THIS MALLOC THE PIXELBUF
// 2 scanlines' worth
// Can the fill function use both scanlines of data?
// So maybe make it 2X half-scanline, malloc'd
// Initialize pixelBuf to 0's
memset(pixelBuf, 0, sizeof(pixelBuf));
lastFillLen = DMA_PIXELS;
dma.setCallback(dma_callback);
return; // Success!
}
// Else delete dptr descriptor here
}
// Else dealloc dma here
}
#endif
}
/**************************************************************************/
/*!
@brief Read one byte from SPI interface (hardware or software)
@returns One byte, MSB order
*/
/**************************************************************************/
uint8_t Adafruit_SPITFT::spiRead() {
if(_sclk < 0){
return HSPI_READ();
}
if(_miso < 0){
return 0;
}
uint8_t r = 0;
for (uint8_t i=0; i<8; i++) {
SSPI_SCK_LOW();
SSPI_SCK_HIGH();
r <<= 1;
if (SSPI_MISO_READ()){
r |= 0x1;
}
}
return r;
}
/**************************************************************************/
/*!
@brief Write one byte to SPI interface (hardware or software)
@param b One byte to send, MSB order
*/
/**************************************************************************/
void Adafruit_SPITFT::spiWrite(uint8_t b) {
if(_sclk < 0){
HSPI_WRITE(b);
return;
}
for(uint8_t bit = 0x80; bit; bit >>= 1){
if((b) & bit){
SSPI_MOSI_HIGH();
} else {
SSPI_MOSI_LOW();
}
SSPI_SCK_LOW();
SSPI_SCK_HIGH();
}
}
/*
* Transaction API
* */
/**************************************************************************/
/*!
@brief Begin an SPI transaction & set CS low.
*/
/**************************************************************************/
void inline Adafruit_SPITFT::startWrite(void){
DMA_WAIT; // Wait for any prior SPI DMA to complete
SPI_BEGIN_TRANSACTION();
SPI_CS_LOW();
}
/**************************************************************************/
/*!
@brief Begin an SPI transaction & set CS high.
*/
/**************************************************************************/
void inline Adafruit_SPITFT::endWrite(void){
#ifdef USE_SPI_DMA
// SPI DMA enabled: wait for DMA completion and end transaction ONLY if
// spitft is NULL. Otherwise, calling function can proceed and
// equivalent code in DMA callback is used.
if(!spitft) {
while(dma_busy); // Wait for DMA operation to complete
SPI_CS_HIGH();
SPI_END_TRANSACTION();
}
#else
SPI_CS_HIGH();
SPI_END_TRANSACTION();
#endif
}
/**************************************************************************/
/*!
@brief Write a command byte (must have a transaction in progress)
@param cmd The 8-bit command to send
*/
/**************************************************************************/
void Adafruit_SPITFT::writeCommand(uint8_t cmd){
SPI_DC_LOW();
spiWrite(cmd);
SPI_DC_HIGH();
}
/**************************************************************************/
/*!
@brief Push a 2-byte color to the framebuffer RAM, will start transaction
@param color 16-bit 5-6-5 Color to draw
*/
/**************************************************************************/
void Adafruit_SPITFT::pushColor(uint16_t color) {
startWrite();
SPI_WRITE16(color);
endWrite();
}
/**************************************************************************/
/*!
@brief Blit multiple 2-byte colors (must have a transaction in progress)
@param colors Array of 16-bit 5-6-5 Colors to draw
@param len How many pixels to draw - 2 bytes per pixel!
*/
/**************************************************************************/
void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len) {
#ifdef USE_SPI_DMA
while(len) {
int count = len;
if(count > DMA_PIXELS) count = DMA_PIXELS;
// Because TFT and SAMD endianisms are different, must swap bytes
// from the 'colors' array passed into a DMA working buffer. This
// can take place while the prior DMA transfer is in progress,
// hence the need for two pixelBufs.
for(int i=0; i<count; i++) {
pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++);
}
// The transfers themselves are relatively small, so we don't
// need a long descriptor list. We just alternate between the
// first two, sharing pixelBufIdx for that purpose.
descriptor[pixelBufIdx].SRCADDR.reg =
(uint32_t)&pixelBuf[pixelBufIdx] + count * 2;
descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1;
descriptor[pixelBufIdx].BTCNT.reg = count * 2;
descriptor[pixelBufIdx].DESCADDR.reg = 0;
while(dma_busy); // NOW wait for prior DMA to complete
// Move new descriptor into place...
memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor));
dma_busy = true;
dma.startJob(); // Trigger SPI DMA transfer
pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
len -= count;
}
#else
SPI_WRITE_PIXELS((uint8_t*)colors , len * 2);
#endif
}
/**************************************************************************/
/*!
@brief Blit a 2-byte color many times (must have a transaction in progress)
@param color The 16-bit 5-6-5 Color to draw
@param len How many pixels to draw
*/
/**************************************************************************/
void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) {
#ifdef USE_SPI_DMA
uint8_t hi = color >> 8,
lo = color;
//while(dma_busy);
if(hi == lo) { // If high and low bytes of color are the same...
pixelBuf[pixelBufIdx][0] = lo * 0x0101;
// Can do this with a relatively short descriptor list,
// each transferring a max of 32767 (not 32768) pixels.
int numDescriptors = (len + 32766) / 32767;
for(int d=0; d<numDescriptors; d++) {
int count = len;
if(count > 32767) count = 32767;
descriptor[d].SRCADDR.reg =
(uint32_t)&pixelBuf[pixelBufIdx];
descriptor[d].BTCTRL.bit.SRCINC = 0;
descriptor[d].BTCNT.reg = count * 2;
descriptor[d].DESCADDR.reg =
(d < (numDescriptors - 1)) ? (uint32_t)&descriptor[d + 1] : 0;
//descriptor[d].DESCADDR.reg = 0;
len -= count;
}
} else {
// If high and low bytes are different, it's necessary to fill
// a buffer with pixel data (swapping high and low bytes because
// TFT and SAMD are different endianisms) and create a longer
// descriptor list pointing repeatedly to this data.
// This can maybe be avoided if color is same as last time and
// length is <= last time. Or should we always fill pixelBuf to a
// known length and then check pixel color?
uint32_t *pixelPtr = (uint32_t *)&pixelBuf[pixelBufIdx];
if(color == lastFillColor) {
if(len > lastFillLen) {
// Work 32 bits (2 pixels) at a time...
uint32_t twoPixels = __builtin_bswap16(color) * 0x00010001;
int fillMin = lastFillLen / 2 + 1;
int fillMax = (((DMA_PIXELS < len) ? DMA_PIXELS : len) + 1) / 2;
for(int i=fillMin; i<fillMax; i++) pixelPtr[i] = twoPixels;
lastFillLen = fillMax * 2;
}
} else {
// Work 32 bits (2 pixels) at a time...
uint32_t twoPixels = __builtin_bswap16(color) * 0x00010001;
int fillCount = (((DMA_PIXELS < len) ? DMA_PIXELS : len) + 1) / 2;
for(int i=0; i<fillCount; i++) pixelPtr[i] = twoPixels;
lastFillLen = fillCount * 2;
}
int numDescriptors = (len + DMA_PIXELS - 1) / DMA_PIXELS;
for(int d=0; d<numDescriptors; d++) {
int count = len;
if(count > DMA_PIXELS) count = DMA_PIXELS;
descriptor[d].SRCADDR.reg =
(uint32_t)pixelPtr + lastFillLen * 2;
descriptor[d].BTCTRL.bit.SRCINC = 1;
descriptor[d].BTCNT.reg = count * 2;
descriptor[d].DESCADDR.reg =
(d < (numDescriptors - 1)) ? (uint32_t)&descriptor[d + 1] : 0;
//descriptor[d].DESCADDR.reg = 0;
len -= count;
}
}
memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor));
dma_busy = true; // ANY function using SPI must poll busy flag!
spitft = this; // Save pointer to Adafruit_SPITFT type for callback
dma.startJob(); // Trigger SPI DMA transfer
pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
#else
#ifdef SPI_HAS_WRITE_PIXELS
if(_sclk >= 0){
for (uint32_t t=0; t<len; t++){
writePixel(color);
}
return;
}
static uint16_t temp[SPI_MAX_PIXELS_AT_ONCE];
size_t blen = (len > SPI_MAX_PIXELS_AT_ONCE)?SPI_MAX_PIXELS_AT_ONCE:len;
uint16_t tlen = 0;
for (uint32_t t=0; t<blen; t++){
temp[t] = color;
}
while(len){
tlen = (len>blen)?blen:len;
writePixels(temp, tlen);
len -= tlen;
}
#else
uint8_t hi = color >> 8, lo = color;
if(_sclk < 0){ //AVR Optimization
for (uint32_t t=len; t; t--){
HSPI_WRITE(hi);
HSPI_WRITE(lo);
}
return;
}
for (uint32_t t=len; t; t--){
spiWrite(hi);
spiWrite(lo);
}
#endif
#endif
}
/**************************************************************************/
/*!
@brief Write a pixel (must have a transaction in progress)
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
DMA_WAIT;
setAddrWindow(x,y,1,1);
writePixel(color);
}
/**************************************************************************/
/*!
@brief Write a filled rectangle (must have a transaction in progress)
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
if((x >= _width) || (y >= _height)) return;
int16_t x2 = x + w - 1, y2 = y + h - 1;
if((x2 < 0) || (y2 < 0)) return;
// Clip left/top
if(x < 0) {
x = 0;
w = x2 + 1;
}
if(y < 0) {
y = 0;
h = y2 + 1;
}
// Clip right/bottom
if(x2 >= _width) w = _width - x;
if(y2 >= _height) h = _height - y;
int32_t len = (int32_t)w * h;
DMA_WAIT;
setAddrWindow(x, y, w, h);
writeColor(color, len);
}
/**************************************************************************/
/*!
@brief Write a perfectly vertical line (must have a transaction in progress)
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
writeFillRect(x, y, 1, h, color);
}
/**************************************************************************/
/*!
@brief Write a perfectly horizontal line (must have a transaction in progress)
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
writeFillRect(x, y, w, 1, color);
}
/**************************************************************************/
/*!
@brief Draw a pixel - sets up transaction
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color){
startWrite();
writePixel(x, y, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Write a perfectly vertical line - sets up transaction
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color) {
startWrite();
writeFastVLine(x, y, h, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Write a perfectly horizontal line - sets up transaction
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color) {
startWrite();
writeFastHLine(x, y, w, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Fill a rectangle completely with one color.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
startWrite();
writeFillRect(x,y,w,h,color);
endWrite();
}
/**************************************************************************/
/*!
@brief Invert the display using built-in hardware command
@param i True if you want to invert, false to make 'normal'
*/
/**************************************************************************/
void Adafruit_SPITFT::invertDisplay(boolean i) {
startWrite();
writeCommand(i ? invertOnCommand : invertOffCommand);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a 16-bit image (RGB 5/6/5) at the specified (x,y) position.
For 16-bit display devices; no color reduction performed.
Adapted from https://github.com/PaulStoffregen/ILI9341_t3
by Marc MERLIN. See examples/pictureEmbed to use this.
5/6/2017: function name and arguments have changed for compatibility
with current GFX library and to avoid naming problems in prior
implementation. Formerly drawBitmap() with arguments in different order.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param pcolors 16-bit array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h) {
int16_t x2, y2; // Lower-right coord
if(( x >= _width ) || // Off-edge right
( y >= _height) || // " top
((x2 = (x+w-1)) < 0 ) || // " left
((y2 = (y+h-1)) < 0) ) return; // " bottom
int16_t bx1=0, by1=0, // Clipped top-left within bitmap
saveW=w; // Save original bitmap width value
if(x < 0) { // Clip left
w += x;
bx1 = -x;
x = 0;
}
if(y < 0) { // Clip top
h += y;
by1 = -y;
y = 0;
}
if(x2 >= _width ) w = _width - x; // Clip right
if(y2 >= _height) h = _height - y; // Clip bottom
pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
startWrite(); // Includes a DMA_WAIT
setAddrWindow(x, y, w, h); // Clipped area
while(h--) { // For each (clipped) scanline...
writePixels(pcolors, w); // Push one (clipped) row
pcolors += saveW; // Advance pointer by one full (unclipped) line
}
endWrite();
}
#endif // !__AVR_ATtiny85__

View File

@ -1,861 +0,0 @@
/*!
* @file Adafruit_SPITFT.cpp
*
* @mainpage Adafruit SPI TFT Displays
*
* @section intro_sec Introduction
This is our library for generic SPI TFT Displays with
address windows and 16 bit color (e.g. ILI9341, HX8357D, ST7735...)
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
* @section dependencies Dependencies
*
* This library depends on <a href="https://github.com/adafruit/Adafruit_GFX">
* Adafruit_GFX</a> being present on your system. Please make sure you have
* installed the latest version before using this library.
*
* @section author Author
*
* Written by Limor "ladyada" Fried for Adafruit Industries.
*
* @section license License
*
* BSD license, all text here must be included in any redistribution.
*
*/
#if !defined(__AVR_ATtiny85__) // NOT A CHANCE of this stuff working on ATtiny
#include "Adafruit_SPITFT.h"
#if !defined(ARDUINO_STM32_FEATHER)
#include "pins_arduino.h"
#endif
#if !defined(ARDUINO_STM32_FEATHER) && !defined(RASPI)
#include "wiring_private.h"
#endif
#include <limits.h>
#ifdef PORT_IOBUS
// On SAMD21, redefine digitalPinToPort() to use the slightly-faster
// PORT_IOBUS rather than PORT (not needed on SAMD51).
#undef digitalPinToPort
#define digitalPinToPort(P) (&(PORT_IOBUS->Group[g_APinDescription[P].ulPort]))
#endif
#include "Adafruit_SPITFT_Macros.h"
#ifdef USE_SPI_DMA
#include <Adafruit_ZeroDMA.h>
#include <malloc.h> // memalign() function
// DMA transfer-in-progress indicator and callback
static volatile boolean dma_busy = false;
static volatile Adafruit_SPITFT *spitft = NULL;
static void dma_callback(Adafruit_ZeroDMA *dma) {
// If spitft pointer is set, deselect TFT and end the SPI transaction
// here in the callback rather than at end of drawing function. Avoids
// a (possibly unnecessary) function call at the start of every graphics
// operation. Can't do this in SPI_BEGIN_TRANSACTION because other code
// outside the library (e.g. SD card reading) may be waiting on the
// GFX SPI transaction to end first.
if(spitft) {
((Adafruit_SPITFT *)spitft)->endWrite();
spitft = NULL;
}
dma_busy = false;
}
/**************************************************************************/
/*!
@brief Poll whether a previous DMA operation is still in-progress.
@return true if SPITFT DMA operation in progress, false if available.
*/
/**************************************************************************/
boolean Adafruit_SPITFT::DMA_busy(void) {
return dma_busy;
}
#define DMA_WAIT while(dma_busy); ///< Wait for dma busy flag to clear
#else
#define DMA_WAIT ///< Do nothing; DMA not used
#endif // USE_SPI_DMA
/**************************************************************************/
/*!
@brief Pass 8-bit (each) R,G,B, get back 16-bit packed color
This function converts 8-8-8 RGB data to 16-bit 5-6-5
@param red Red 8 bit color
@param green Green 8 bit color
@param blue Blue 8 bit color
@return Unsigned 16-bit down-sampled color in 5-6-5 format
*/
/**************************************************************************/
uint16_t Adafruit_SPITFT::color565(uint8_t red, uint8_t green, uint8_t blue) {
return ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | ((blue & 0xF8) >> 3);
}
/**************************************************************************/
/*!
@brief Instantiate Adafruit SPI display driver with software SPI
@param w Display width in pixels
@param h Display height in pixels
@param cs Chip select pin #
@param dc Data/Command pin #
@param mosi SPI MOSI pin #
@param sclk SPI Clock pin #
@param rst Reset pin # (optional, pass -1 if unused)
@param miso SPI MISO pin # (optional, pass -1 if unused)
*/
/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h,
int8_t cs, int8_t dc, int8_t mosi,
int8_t sclk, int8_t rst, int8_t miso)
: Adafruit_GFX(w, h) {
_cs = cs;
_dc = dc;
_rst = rst;
_sclk = sclk;
_mosi = mosi;
_miso = miso;
_freq = 0;
#ifdef USE_FAST_PINIO
dcport = (RwReg *)portOutputRegister(digitalPinToPort(dc));
dcpinmask = digitalPinToBitMask(dc);
clkport = (RwReg *)portOutputRegister(digitalPinToPort(sclk));
clkpinmask = digitalPinToBitMask(sclk);
mosiport = (RwReg *)portOutputRegister(digitalPinToPort(mosi));
mosipinmask = digitalPinToBitMask(mosi);
if(miso >= 0){
misoport = (RwReg *)portInputRegister(digitalPinToPort(miso));
misopinmask = digitalPinToBitMask(miso);
} else {
misoport = 0;
misopinmask = 0;
}
if(cs >= 0) {
csport = (RwReg *)portOutputRegister(digitalPinToPort(cs));
cspinmask = digitalPinToBitMask(cs);
} else {
// No chip-select line defined; might be permanently tied to GND.
// Assign a valid GPIO register (though not used for CS), and an
// empty pin bitmask...the nonsense bit-twiddling might be faster
// than checking _cs and possibly branching.
csport = dcport;
cspinmask = 0;
}
#endif
}
/**************************************************************************/
/*!
@brief Instantiate Adafruit SPI display driver with hardware SPI
@param w Display width in pixels
@param h Display height in pixels
@param cs Chip select pin #
@param dc Data/Command pin #
@param rst Reset pin # (optional, pass -1 if unused)
*/
/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h,
int8_t cs, int8_t dc, int8_t rst)
: Adafruit_SPITFT(w, h, &SPI, cs, dc, rst)
{
// We just call the hardware SPI instantiator with the default SPI device (&SPI)
}
/**************************************************************************/
/*!
@brief Instantiate Adafruit SPI display driver with hardware SPI
@param w Display width in pixels
@param h Display height in pixels
@param spiClass A pointer to an SPI hardware interface, e.g. &SPI1
@param cs Chip select pin #
@param dc Data/Command pin #
@param rst Reset pin # (optional, pass -1 if unused)
*/
/**************************************************************************/
Adafruit_SPITFT::Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass,
int8_t cs, int8_t dc, int8_t rst)
: Adafruit_GFX(w, h) {
_cs = cs;
_dc = dc;
_rst = rst;
_spi = spiClass;
_sclk = -1;
_mosi = -1;
_miso = -1;
_freq = 0;
#ifdef USE_FAST_PINIO
clkport = 0;
clkpinmask = 0;
mosiport = 0;
mosipinmask = 0;
misoport = 0;
misopinmask = 0;
dcport = (RwReg *)portOutputRegister(digitalPinToPort(dc));
dcpinmask = digitalPinToBitMask(dc);
if(cs >= 0) {
csport = (RwReg *)portOutputRegister(digitalPinToPort(cs));
cspinmask = digitalPinToBitMask(cs);
} else {
// See notes in prior constructor.
csport = dcport;
cspinmask = 0;
}
#endif
}
/**************************************************************************/
/*!
@brief Initialiaze the SPI interface (hardware or software)
@param freq The desired maximum SPI hardware clock frequency
*/
/**************************************************************************/
void Adafruit_SPITFT::initSPI(uint32_t freq) {
_freq = freq;
// Control Pins
if(_cs >= 0) {
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH); // Deselect
}
pinMode(_dc, OUTPUT);
digitalWrite(_dc, LOW);
// Software SPI
if(_sclk >= 0){
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, LOW);
pinMode(_sclk, OUTPUT);
digitalWrite(_sclk, HIGH);
if(_miso >= 0){
pinMode(_miso, INPUT);
}
}
// Hardware SPI
SPI_BEGIN();
// toggle RST low to reset
if (_rst >= 0) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
digitalWrite(_rst, LOW);
delay(100);
digitalWrite(_rst, HIGH);
delay(200);
}
#ifdef USE_SPI_DMA
// INITIALIZE DMA
if(dma.allocate() == DMA_STATUS_OK) { // Allocate channel
// The DMA library needs to allocate at least one valid descriptor,
// so we do that here. It's not used in the usual sense though,
// just before a transfer we copy descriptor[0] to this address.
if(dptr = dma.addDescriptor(NULL, NULL, 42, DMA_BEAT_SIZE_BYTE,
false, false)) {
// Allocate 2 scanlines worth of pixels on display's major axis,
// whichever that is, rounding each up to 2-pixel boundary.
int major = (WIDTH > HEIGHT) ? WIDTH : HEIGHT;
major += (major & 1); // -> next 2-pixel bound, if needed.
maxFillLen = major * 2; // 2 scanlines
// Note to future self: if you decide to make the pixel buffer
// much larger, remember that DMA transfer descriptors can't
// exceed 65,535 bytes (not 65,536), meaning 32,767 pixels tops.
// Not that we have that kind of RAM to throw around right now.
if((pixelBuf[0] =
(uint16_t *)malloc(maxFillLen * sizeof(uint16_t)))) {
// Alloc OK. Get pointer to start of second scanline.
pixelBuf[1] = &pixelBuf[0][major];
// Determine number of DMA descriptors needed to cover
// entire screen when entire 2-line pixelBuf is used
// (round up for fractional last descriptor).
int numDescriptors = (WIDTH * HEIGHT + (maxFillLen - 1)) /
maxFillLen;
// DMA descriptors MUST be 128-bit (16 byte) aligned.
// memalign() is considered 'obsolete' but it's replacements
// (aligned_alloc() or posix_memalign()) are not currently
// available in the version of ARM GCC in use, but this is,
// so here we are.
if((descriptor = (DmacDescriptor *)memalign(16,
numDescriptors * sizeof(DmacDescriptor)))) {
int dmac_id;
volatile uint32_t *data_reg;
// THIS IS AN AFFRONT TO NATURE, but I don't know
// any "clean" way to get the sercom number from the
// SPIClass pointer (e.g. &SPI or &SPI1), which is
// all we have to work with. SPIClass does contain
// a SERCOM pointer but it is a PRIVATE member!
// Doing an UNSPEAKABLY HORRIBLE THING here, directly
// accessing the first 32-bit value in the SPIClass
// structure, knowing that's (currently) where the
// SERCOM pointer lives, but this ENTIRELY DEPENDS
// on that structure not changing nor the compiler
// rearranging things. Oh the humanity!
if(*(SERCOM **)_spi == &sercom0) {
dmac_id = SERCOM0_DMAC_ID_TX;
data_reg = &SERCOM0->SPI.DATA.reg;
#if defined SERCOM1
} else if(*(SERCOM **)_spi == &sercom1) {
dmac_id = SERCOM1_DMAC_ID_TX;
data_reg = &SERCOM1->SPI.DATA.reg;
#endif
#if defined SERCOM2
} else if(*(SERCOM **)_spi == &sercom2) {
dmac_id = SERCOM2_DMAC_ID_TX;
data_reg = &SERCOM2->SPI.DATA.reg;
#endif
#if defined SERCOM3
} else if(*(SERCOM **)_spi == &sercom3) {
dmac_id = SERCOM3_DMAC_ID_TX;
data_reg = &SERCOM3->SPI.DATA.reg;
#endif
#if defined SERCOM4
} else if(*(SERCOM **)_spi == &sercom4) {
dmac_id = SERCOM4_DMAC_ID_TX;
data_reg = &SERCOM4->SPI.DATA.reg;
#endif
#if defined SERCOM5
} else if(*(SERCOM **)_spi == &sercom5) {
dmac_id = SERCOM5_DMAC_ID_TX;
data_reg = &SERCOM5->SPI.DATA.reg;
#endif
}
dma.setTrigger(dmac_id);
dma.setAction(DMA_TRIGGER_ACTON_BEAT);
// Initialize descriptor list.
for(int d=0; d<numDescriptors; d++) {
// No need to set SRCADDR, DESCADDR or BTCNT --
// those are done in the pixel-writing functions.
descriptor[d].BTCTRL.bit.VALID = true;
descriptor[d].BTCTRL.bit.EVOSEL =
DMA_EVENT_OUTPUT_DISABLE;
descriptor[d].BTCTRL.bit.BLOCKACT =
DMA_BLOCK_ACTION_NOACT;
descriptor[d].BTCTRL.bit.BEATSIZE = DMA_BEAT_SIZE_BYTE;
descriptor[d].BTCTRL.bit.DSTINC = 0;
descriptor[d].BTCTRL.bit.STEPSEL = DMA_STEPSEL_SRC;
descriptor[d].BTCTRL.bit.STEPSIZE =
DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
descriptor[d].DSTADDR.reg = (uint32_t)data_reg;
}
lastFillColor = 0x0000;
lastFillLen = 0;
dma.setCallback(dma_callback);
return; // Success!
}
// Else some alloc/init error along the way...clean up...
free(pixelBuf[0]);
pixelBuf[0] = pixelBuf[1] = NULL;
}
// Don't currently have a descriptor delete function in
// ZeroDMA lib, but if we did, it would be called here.
}
dma.free(); // Deallocate DMA channel
}
#endif // end DMA init
}
/**************************************************************************/
/*!
@brief Read one byte from SPI interface (hardware or software)
@returns One byte, MSB order
*/
/**************************************************************************/
uint8_t Adafruit_SPITFT::spiRead() {
if(_sclk < 0){
return HSPI_READ();
}
if(_miso < 0){
return 0;
}
uint8_t r = 0;
for (uint8_t i=0; i<8; i++) {
SSPI_SCK_LOW();
SSPI_SCK_HIGH();
r <<= 1;
if (SSPI_MISO_READ()){
r |= 0x1;
}
}
return r;
}
/**************************************************************************/
/*!
@brief Write one byte to SPI interface (hardware or software)
@param b One byte to send, MSB order
*/
/**************************************************************************/
void Adafruit_SPITFT::spiWrite(uint8_t b) {
if(_sclk < 0){
HSPI_WRITE(b);
return;
}
for(uint8_t bit = 0x80; bit; bit >>= 1){
if((b) & bit){
SSPI_MOSI_HIGH();
} else {
SSPI_MOSI_LOW();
}
SSPI_SCK_LOW();
SSPI_SCK_HIGH();
}
}
/*
* Transaction API
* */
/**************************************************************************/
/*!
@brief Begin an SPI transaction & set CS low.
*/
/**************************************************************************/
void inline Adafruit_SPITFT::startWrite(void){
DMA_WAIT; // Wait for any prior SPI DMA to complete
SPI_BEGIN_TRANSACTION();
SPI_CS_LOW();
}
/**************************************************************************/
/*!
@brief Begin an SPI transaction & set CS high.
*/
/**************************************************************************/
void inline Adafruit_SPITFT::endWrite(void){
#ifdef USE_SPI_DMA
// SPI DMA enabled: wait for DMA completion and end transaction ONLY if
// spitft is NULL. Otherwise, calling function can proceed and
// equivalent code in DMA callback is used.
if(!spitft) {
DMA_WAIT; // Wait for DMA operation to complete
SPI_CS_HIGH();
SPI_END_TRANSACTION();
}
#else
SPI_CS_HIGH();
SPI_END_TRANSACTION();
#endif
}
/**************************************************************************/
/*!
@brief Write a command byte (must have a transaction in progress)
@param cmd The 8-bit command to send
*/
/**************************************************************************/
void Adafruit_SPITFT::writeCommand(uint8_t cmd){
SPI_DC_LOW();
spiWrite(cmd);
SPI_DC_HIGH();
}
/**************************************************************************/
/*!
@brief Push a 2-byte color to the framebuffer RAM, will start transaction
@param color 16-bit 5-6-5 Color to draw
*/
/**************************************************************************/
void Adafruit_SPITFT::pushColor(uint16_t color) {
startWrite();
SPI_WRITE16(color);
endWrite();
}
/**************************************************************************/
/*!
@brief Blit multiple 2-byte colors (must have a transaction in progress)
@param colors Array of 16-bit 5-6-5 Colors to draw
@param len How many pixels to draw - 2 bytes per pixel!
*/
/**************************************************************************/
void Adafruit_SPITFT::writePixels(uint16_t *colors, uint32_t len) {
#ifdef USE_SPI_DMA
int maxSpan = maxFillLen / 2; // One scanline max
uint8_t pixelBufIdx = 0; // Active pixel buffer number
while(len) {
int count = (len < maxSpan) ? len : maxSpan;
// Because TFT and SAMD endianisms are different, must swap bytes
// from the 'colors' array passed into a DMA working buffer. This
// can take place while the prior DMA transfer is in progress,
// hence the need for two pixelBufs.
for(int i=0; i<count; i++) {
pixelBuf[pixelBufIdx][i] = __builtin_bswap16(*colors++);
}
// The transfers themselves are relatively small, so we don't
// need a long descriptor list. We just alternate between the
// first two, sharing pixelBufIdx for that purpose.
descriptor[pixelBufIdx].SRCADDR.reg =
(uint32_t)pixelBuf[pixelBufIdx] + count * 2;
descriptor[pixelBufIdx].BTCTRL.bit.SRCINC = 1;
descriptor[pixelBufIdx].BTCNT.reg = count * 2;
descriptor[pixelBufIdx].DESCADDR.reg = 0;
DMA_WAIT; // NOW wait for prior DMA to complete
// Move new descriptor into place...
memcpy(dptr, &descriptor[pixelBufIdx], sizeof(DmacDescriptor));
dma_busy = true;
dma.startJob(); // Trigger SPI DMA transfer
pixelBufIdx = 1 - pixelBufIdx; // Swap DMA pixel buffers
len -= count;
}
lastFillColor = 0x0000; // pixelBuf has been sullied
lastFillLen = 0;
// Return immediately -- other code runs with last DMA transfer in
// background. startWrite() will wait for the transfer to complete
// before issuing any more commands. User code MUST poll
// display.DMA_busy() before attempting anything else on the same
// SPI bus (e.g. SD card access).
#else
SPI_WRITE_PIXELS((uint8_t*)colors , len * 2);
#endif
}
/**************************************************************************/
/*!
@brief Blit a 2-byte color many times (must have a transaction in progress)
@param color The 16-bit 5-6-5 Color to draw
@param len How many pixels to draw
*/
/**************************************************************************/
void Adafruit_SPITFT::writeColor(uint16_t color, uint32_t len) {
#ifdef USE_SPI_DMA
if((color >> 8) == (color & 0xFF)) { // If high & low bytes are same...
onePixelBuf = color;
// Can do this with a relatively short descriptor list,
// each transferring a max of 32,767 (not 32,768) pixels.
// This won't run off the end of the allocated descriptor list,
// since we're using much larger chunks per descriptor here.
int numDescriptors = (len + 32766) / 32767;
for(int d=0; d<numDescriptors; d++) {
int count = (len > 32767) ? 32767 : len;
descriptor[d].SRCADDR.reg = (uint32_t)&onePixelBuf;
descriptor[d].BTCTRL.bit.SRCINC = 0;
descriptor[d].BTCNT.reg = count * 2;
descriptor[d].DESCADDR.reg =
(d < (numDescriptors - 1)) ? (uint32_t)&descriptor[d + 1] : 0;
len -= count;
}
} else {
// If high and low bytes are distinct, it's necessary to fill
// a buffer with pixel data (swapping high and low bytes because
// TFT and SAMD are different endianisms) and create a longer
// descriptor list pointing repeatedly to this data. We can do
// this slightly faster working 2 pixels (32 bits) at a time.
uint32_t *pixelPtr = (uint32_t *)pixelBuf[0],
twoPixels = __builtin_bswap16(color) * 0x00010001;
// We can avoid some or all of the buffer-filling if the color
// is the same as last time...
if(color == lastFillColor) {
// If length is longer than prior instance, fill only the
// additional pixels in the buffer and update lastFillLen.
if(len > lastFillLen) {
int fillStart = lastFillLen / 2 + 1,
fillEnd = (((maxFillLen < len) ?
maxFillLen : len) + 1) / 2;
for(int i=fillStart; i<fillEnd; i++) pixelPtr[i] = twoPixels;
lastFillLen = fillEnd * 2;
} // else do nothing, don't set pixels, don't change lastFillLen
} else {
int fillEnd = (((maxFillLen < len) ?
maxFillLen : len) + 1) / 2;
for(int i=0; i<fillEnd; i++) pixelPtr[i] = twoPixels;
lastFillLen = fillEnd * 2;
}
int numDescriptors = (len + maxFillLen - 1) / maxFillLen;
for(int d=0; d<numDescriptors; d++) {
int count = lastFillLen * 2; // Transfer size in bytes
descriptor[d].SRCADDR.reg = (uint32_t)pixelPtr + count;
descriptor[d].BTCTRL.bit.SRCINC = 1;
descriptor[d].BTCNT.reg = count;
descriptor[d].DESCADDR.reg =
(d < (numDescriptors - 1)) ? (uint32_t)&descriptor[d + 1] : 0;
len -= count;
}
}
memcpy(dptr, &descriptor[0], sizeof(DmacDescriptor));
dma_busy = true; // ANY function using SPI must poll busy flag!
spitft = this; // Save pointer to Adafruit_SPITFT type for callback
dma.startJob(); // Trigger SPI DMA transfer
// Return immediately -- other code runs with DMA transfer in
// background. startWrite() will wait for the transfer to complete
// before issuing any more commands. User code MUST poll
// display.DMA_busy() before attempting anything else on the same
// SPI bus (e.g. SD card access).
#else // Non-DMA
#ifdef SPI_HAS_WRITE_PIXELS
if(_sclk >= 0){
for (uint32_t t=0; t<len; t++){
writePixel(color);
}
return;
}
static uint16_t temp[SPI_MAX_PIXELS_AT_ONCE];
size_t blen = (len > SPI_MAX_PIXELS_AT_ONCE)?SPI_MAX_PIXELS_AT_ONCE:len;
uint16_t tlen = 0;
for (uint32_t t=0; t<blen; t++){
temp[t] = color;
}
while(len){
tlen = (len>blen)?blen:len;
writePixels(temp, tlen);
len -= tlen;
}
#else
uint8_t hi = color >> 8, lo = color;
if(_sclk < 0){ //AVR Optimization
for (uint32_t t=len; t; t--){
HSPI_WRITE(hi);
HSPI_WRITE(lo);
}
return;
}
for (uint32_t t=len; t; t--){
spiWrite(hi);
spiWrite(lo);
}
#endif
#endif // end non-DMA
}
/**************************************************************************/
/*!
@brief Write a pixel (must have a transaction in progress)
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_SPITFT::writePixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
DMA_WAIT;
setAddrWindow(x,y,1,1);
writePixel(color);
}
/**************************************************************************/
/*!
@brief Write a filled rectangle (must have a transaction in progress)
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
if((x >= _width) || (y >= _height)) return;
int16_t x2 = x + w - 1, y2 = y + h - 1;
if((x2 < 0) || (y2 < 0)) return;
// Clip left/top
if(x < 0) {
x = 0;
w = x2 + 1;
}
if(y < 0) {
y = 0;
h = y2 + 1;
}
// Clip right/bottom
if(x2 >= _width) w = _width - x;
if(y2 >= _height) h = _height - y;
int32_t len = (int32_t)w * h;
DMA_WAIT;
setAddrWindow(x, y, w, h);
writeColor(color, len);
}
/**************************************************************************/
/*!
@brief Write a perfectly vertical line (must have a transaction in progress)
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void inline Adafruit_SPITFT::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
writeFillRect(x, y, 1, h, color);
}
/**************************************************************************/
/*!
@brief Write a perfectly horizontal line (must have a transaction in progress)
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void inline Adafruit_SPITFT::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
writeFillRect(x, y, w, 1, color);
}
/**************************************************************************/
/*!
@brief Draw a pixel - sets up transaction
@param x x coordinate
@param y y coordinate
@param color 16-bit 5-6-5 Color to draw with
*/
/**************************************************************************/
void Adafruit_SPITFT::drawPixel(int16_t x, int16_t y, uint16_t color){
// Clip first...
if((x >= 0) && (x < _width) && (y >= 0) && (y < _height)) {
// THEN set up transaction (if needed) and draw...
startWrite();
setAddrWindow(x, y, 1, 1);
writePixel(color);
endWrite();
}
}
/**************************************************************************/
/*!
@brief Write a perfectly vertical line - sets up transaction
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::drawFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color) {
startWrite();
writeFastVLine(x, y, h, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Write a perfectly horizontal line - sets up transaction
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::drawFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color) {
startWrite();
writeFastHLine(x, y, w, color);
endWrite();
}
/**************************************************************************/
/*!
@brief Fill a rectangle completely with one color.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void Adafruit_SPITFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
startWrite();
writeFillRect(x,y,w,h,color);
endWrite();
}
/**************************************************************************/
/*!
@brief Invert the display using built-in hardware command
@param i True if you want to invert, false to make 'normal'
*/
/**************************************************************************/
void Adafruit_SPITFT::invertDisplay(boolean i) {
startWrite();
writeCommand(i ? invertOnCommand : invertOffCommand);
endWrite();
}
/**************************************************************************/
/*!
@brief Draw a 16-bit image (RGB 5/6/5) at the specified (x,y) position.
For 16-bit display devices; no color reduction performed.
Adapted from https://github.com/PaulStoffregen/ILI9341_t3
by Marc MERLIN. See examples/pictureEmbed to use this.
5/6/2017: function name and arguments have changed for compatibility
with current GFX library and to avoid naming problems in prior
implementation. Formerly drawBitmap() with arguments in different order.
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param pcolors 16-bit array with 16-bit color bitmap
@param w Width of bitmap in pixels
@param h Height of bitmap in pixels
*/
/**************************************************************************/
void Adafruit_SPITFT::drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h) {
int16_t x2, y2; // Lower-right coord
if(( x >= _width ) || // Off-edge right
( y >= _height) || // " top
((x2 = (x+w-1)) < 0 ) || // " left
((y2 = (y+h-1)) < 0) ) return; // " bottom
int16_t bx1=0, by1=0, // Clipped top-left within bitmap
saveW=w; // Save original bitmap width value
if(x < 0) { // Clip left
w += x;
bx1 = -x;
x = 0;
}
if(y < 0) { // Clip top
h += y;
by1 = -y;
y = 0;
}
if(x2 >= _width ) w = _width - x; // Clip right
if(y2 >= _height) h = _height - y; // Clip bottom
pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
startWrite(); // Includes a DMA_WAIT
setAddrWindow(x, y, w, h); // Clipped area
while(h--) { // For each (clipped) scanline...
writePixels(pcolors, w); // Push one (clipped) row
pcolors += saveW; // Advance pointer by one full (unclipped) line
}
endWrite();
}
#endif // !__AVR_ATtiny85__

View File

@ -1,153 +0,0 @@
#ifndef _ADAFRUIT_SPITFT_
#define _ADAFRUIT_SPITFT_
#if !defined(__AVR_ATtiny85__) // NOT A CHANCE of this stuff working on ATtiny
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
#include <SPI.h>
#include "Adafruit_GFX.h"
#define USE_FAST_PINIO ///< If set, use PORT access instead of digitalWrite()
#define USE_SPI_DMA ///< If set, use SPI DMA if supported
#define DMA_PIXELS 256
#if !defined(ARDUINO_ARCH_SAMD)
#undef USE_SPI_DMA ///< Only for SAMD chips
#endif
#ifdef USE_SPI_DMA
#include <Adafruit_ZeroDMA.h>
#endif
#if defined(__AVR__)
typedef volatile uint8_t RwReg;
#elif defined(ARDUINO_STM32_FEATHER)
typedef volatile uint32 RwReg;
#undef USE_FAST_PINIO
typedef class HardwareSPI SPIClass;
#elif defined(__OPENCR__) || defined (__OPENCM904__)
#undef USE_FAST_PINIO
#elif defined(ARDUINO_FEATHER52) || defined(__arm__)
typedef volatile uint32_t RwReg;
#elif defined(ESP32) || defined(ESP8266)
typedef volatile uint32_t RwReg;
#undef USE_FAST_PINIO
#else
#undef USE_FAST_PINIO
#endif
#include "Adafruit_SPITFT_Macros.h"
/// A heavily optimized SPI display subclass of GFX. Manages SPI bitbanging, transactions, DMA, etc! Despite being called SPITFT, the classic SPI data/command interface is also used by OLEDs.
class Adafruit_SPITFT : public Adafruit_GFX {
public:
Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, int8_t _RST = -1, int8_t _MISO = -1);
Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _RST = -1);
Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t _CS, int8_t _DC, int8_t _RST = -1);
virtual void begin(uint32_t freq) = 0; ///< Virtual begin() function to set SPI frequency, must be overridden in subclass. @param freq Maximum SPI hardware clock speed
void initSPI(uint32_t freq);
// Required Non-Transaction
void drawPixel(int16_t x, int16_t y, uint16_t color);
// Transaction API
void startWrite(void);
void endWrite(void);
void writePixel(int16_t x, int16_t y, uint16_t color);
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
// Transaction API not used by GFX
/*!
@brief SPI displays set an address window rectangle for blitting pixels
@param x Top left corner x coordinate
@param y Top left corner x coordinate
@param w Width of window
@param h Height of window
*/
virtual void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0;
/*!
@brief Write a 2-byte color (must have a transaction in progress)
@param color 16-bit 5-6-5 Color to draw
*/
void inline writePixel(uint16_t color) { SPI_WRITE16(color); }
void writePixels(uint16_t * colors, uint32_t len);
void writeColor(uint16_t color, uint32_t len);
void pushColor(uint16_t color);
// Recommended Non-Transaction
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
using Adafruit_GFX::drawRGBBitmap; // Check base class first
void drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h);
void invertDisplay(boolean i);
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
void writeCommand(uint8_t cmd);
void spiWrite(uint8_t v);
uint8_t spiRead(void);
#ifdef USE_SPI_DMA
boolean DMA_busy(void);
#endif
protected:
SPIClass *_spi; ///< The SPI device we want to use (set in constructor)
uint32_t _freq; ///< SPI clock frequency (for hardware SPI)
#if defined (__AVR__) || defined(TEENSYDUINO) || defined (ESP8266) || defined (ESP32)
int8_t _cs, _dc, _rst, _sclk, _mosi, _miso;
#else
int32_t _cs, ///< Arduino pin # for chip-select pin
_dc, ///< Arduino pin # for data-command pin
_rst, ///< Arduino pin # for reset pin
_sclk, ///< Arduino pin # for SPI clock pin
_mosi, ///< Arduino pin # for SPI MOSI pin
_miso; ///< Arduino pin # for SPI MISO pin
#endif
#ifdef USE_FAST_PINIO
volatile RwReg *mosiport, ///< Direct chip register for toggling MOSI with fast bitbang IO
*misoport, ///< Direct chip register for toggling MISO with fast bitbang IO
*clkport, ///< Direct chip register for toggling CLK with fast bitbang IO
*dcport, ///< Direct chip register for toggling DC with fast bitbang IO
*csport; ///< Direct chip register for toggling CS with fast bitbang IO
RwReg mosipinmask, ///< bitmask for turning on/off MOSI with fast register bitbang IO
misopinmask, ///< bitmask for turning on/off MISO with fast register bitbang IO
clkpinmask, ///< bitmask for turning on/off CLK with fast register bitbang IO
cspinmask, ///< bitmask for turning on/off CS with fast register bitbang IO
dcpinmask; ///< bitmask for turning on/off DC with fast register bitbang IO
#endif
uint8_t invertOnCommand = 0, ///< SPI command byte to turn on invert
invertOffCommand = 0; ///< SPI command byte to turn off invert
int16_t _xstart = 0; ///< Many displays don't have pixels starting at (0,0) of the internal framebuffer, this is the x offset from 0 to align
int16_t _ystart = 0; ///< Many displays don't have pixels starting at (0,0) of the internal framebuffer, this is the y offset from 0 to align
#ifdef USE_SPI_DMA
Adafruit_ZeroDMA dma; ///< DMA instance
DmacDescriptor *dptr = NULL; ///< 1st descriptor
DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list
// uint16_t *pixelBuf[2]; ///< Working buffers
uint16_t pixelBuf[2][DMA_PIXELS]; ///< Working buffers
uint8_t pixelBufIdx = 0; ///< Active buffer #
uint16_t lastFillColor = 0; ///< Last color used in fill func
uint32_t lastFillLen = 0; ///< # of pixels w/lastFillColor
#endif
};
#endif // !__AVR_ATtiny85__
#endif // !_ADAFRUIT_SPITFT_

View File

@ -1,158 +0,0 @@
#ifndef _ADAFRUIT_SPITFT_
#define _ADAFRUIT_SPITFT_
#if !defined(__AVR_ATtiny85__) // NOT A CHANCE of this stuff working on ATtiny
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
#include <SPI.h>
#include "Adafruit_GFX.h"
#define USE_FAST_PINIO ///< If set, use PORT access instead of digitalWrite()
#define USE_SPI_DMA ///< If set, use SPI DMA if available
// If DMA is enabled, Arduino sketch MUST #include <Adafruit_ZeroDMA.h>
// Sketches MUST poll tft.DMA_busy() before doing other things that work
// on the SPI bus (e.g. accessing SD card).
// Estimated RAM usage:
// 4 bytes/pixel on display major axis + 8 bytes/pixel on minor axis,
// e.g. 320x240 pixels = 320 * 4 + 240 * 8 = 3,200 bytes.
#if !defined(ARDUINO_ARCH_SAMD)
#undef USE_SPI_DMA ///< Only for SAMD chips
#endif
#ifdef USE_SPI_DMA
#include <Adafruit_ZeroDMA.h>
#endif
#if defined(__AVR__)
typedef volatile uint8_t RwReg;
#elif defined(ARDUINO_STM32_FEATHER)
typedef volatile uint32 RwReg;
#undef USE_FAST_PINIO
typedef class HardwareSPI SPIClass;
#elif defined(__OPENCR__) || defined (__OPENCM904__)
#undef USE_FAST_PINIO
#elif defined(ARDUINO_FEATHER52) || defined(__arm__)
typedef volatile uint32_t RwReg;
#elif defined(ESP32) || defined(ESP8266)
typedef volatile uint32_t RwReg;
#undef USE_FAST_PINIO
#else
#undef USE_FAST_PINIO
#endif
#include "Adafruit_SPITFT_Macros.h"
/// A heavily optimized SPI display subclass of GFX. Manages SPI bitbanging, transactions, DMA, etc! Despite being called SPITFT, the classic SPI data/command interface is also used by OLEDs.
class Adafruit_SPITFT : public Adafruit_GFX {
public:
Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, int8_t _RST = -1, int8_t _MISO = -1);
Adafruit_SPITFT(uint16_t w, uint16_t h, int8_t _CS, int8_t _DC, int8_t _RST = -1);
Adafruit_SPITFT(uint16_t w, uint16_t h, SPIClass *spiClass, int8_t _CS, int8_t _DC, int8_t _RST = -1);
virtual void begin(uint32_t freq) = 0; ///< Virtual begin() function to set SPI frequency, must be overridden in subclass. @param freq Maximum SPI hardware clock speed
void initSPI(uint32_t freq);
// Required Non-Transaction
void drawPixel(int16_t x, int16_t y, uint16_t color);
// Transaction API
void startWrite(void);
void endWrite(void);
void writePixel(int16_t x, int16_t y, uint16_t color);
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
// Transaction API not used by GFX
/*!
@brief SPI displays set an address window rectangle for blitting pixels
@param x Top left corner x coordinate
@param y Top left corner x coordinate
@param w Width of window
@param h Height of window
*/
virtual void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h) = 0;
/*!
@brief Write a 2-byte color (must have a transaction in progress)
@param color 16-bit 5-6-5 Color to draw
*/
void inline writePixel(uint16_t color) { SPI_WRITE16(color); }
void writePixels(uint16_t * colors, uint32_t len);
void writeColor(uint16_t color, uint32_t len);
void pushColor(uint16_t color);
// Recommended Non-Transaction
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
using Adafruit_GFX::drawRGBBitmap; // Check base class first
void drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h);
void invertDisplay(boolean i);
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
void writeCommand(uint8_t cmd);
void spiWrite(uint8_t v);
uint8_t spiRead(void);
#ifdef USE_SPI_DMA
boolean DMA_busy(void);
#endif
protected:
SPIClass *_spi; ///< The SPI device we want to use (set in constructor)
uint32_t _freq; ///< SPI clock frequency (for hardware SPI)
#if defined (__AVR__) || defined(TEENSYDUINO) || defined (ESP8266) || defined (ESP32)
int8_t _cs, _dc, _rst, _sclk, _mosi, _miso;
#else
int32_t _cs, ///< Arduino pin # for chip-select pin
_dc, ///< Arduino pin # for data-command pin
_rst, ///< Arduino pin # for reset pin
_sclk, ///< Arduino pin # for SPI clock pin
_mosi, ///< Arduino pin # for SPI MOSI pin
_miso; ///< Arduino pin # for SPI MISO pin
#endif
#ifdef USE_FAST_PINIO
volatile RwReg *mosiport, ///< Direct chip register for toggling MOSI with fast bitbang IO
*misoport, ///< Direct chip register for toggling MISO with fast bitbang IO
*clkport, ///< Direct chip register for toggling CLK with fast bitbang IO
*dcport, ///< Direct chip register for toggling DC with fast bitbang IO
*csport; ///< Direct chip register for toggling CS with fast bitbang IO
RwReg mosipinmask, ///< bitmask for turning on/off MOSI with fast register bitbang IO
misopinmask, ///< bitmask for turning on/off MISO with fast register bitbang IO
clkpinmask, ///< bitmask for turning on/off CLK with fast register bitbang IO
cspinmask, ///< bitmask for turning on/off CS with fast register bitbang IO
dcpinmask; ///< bitmask for turning on/off DC with fast register bitbang IO
#endif
uint8_t invertOnCommand = 0, ///< SPI command byte to turn on invert
invertOffCommand = 0; ///< SPI command byte to turn off invert
int16_t _xstart = 0; ///< Many displays don't have pixels starting at (0,0) of the internal framebuffer, this is the x offset from 0 to align
int16_t _ystart = 0; ///< Many displays don't have pixels starting at (0,0) of the internal framebuffer, this is the y offset from 0 to align
#ifdef USE_SPI_DMA
Adafruit_ZeroDMA dma; ///< DMA instance
DmacDescriptor *dptr = NULL; ///< 1st descriptor
DmacDescriptor *descriptor = NULL; ///< Allocated descriptor list
uint16_t *pixelBuf[2]; ///< Working buffers
uint16_t maxFillLen; ///< Max pixels per DMA xfer
uint16_t lastFillColor = 0; ///< Last color used w/fill
uint32_t lastFillLen = 0; ///< # of pixels w/last fill
uint8_t onePixelBuf; ///< For hi==lo fill
#endif
};
#endif // !__AVR_ATtiny85__
#endif // !_ADAFRUIT_SPITFT_

View File

@ -1,28 +0,0 @@
BENCHMARK TIME (MICROSECONDS)
NO DMA W/DMA SPEEDUP
Screen fill 1423496 513050 2.7X
Text 95811 97996 1X
Lines 844297 845960 1X
Horiz/Vert Lines 118764 47679 2.5X
Rectangles (outline) 75930 33124 2.3X
Rectangles (filled) 2955105 1087729 2.7X
Circles (filled) 374061 301426 1.2X
Circles (outline) 368583 367738 1X
Triangles (outline) 190206 183978 1X
Triangles (filled) 1004699 477874 2.1X
Rounded rects (outline) 164752 543676 0.3X WTF?
Rounded rects (filled) 2950025 1895088 1.6X
M4:
Screen fill 771834 512267 1.5X
Text 44791 43447 1X
Lines 410014 409999 1X
Horiz/Vert Lines 63649 43144 1.5X
Rectangles (outline) 40636 27330 1.5X
Rectangles (filled) 1601076 1064273 1.5X
Circles (filled) 192210 157732 1.2X
Circles (outline) 179822 179750 1X
Triangles (outline) 93047 91328 1X
Triangles (filled) 528396 373338 1.4X
Rounded rects (outline) 82508 73489 1.1X
Rounded rects (filled) 1595105 1060465 1.5X