From 7e41e0d11bd20e75eb29805e536750558a4e559a Mon Sep 17 00:00:00 2001 From: victorpv Date: Wed, 18 Mar 2015 08:55:11 -0500 Subject: [PATCH] These are the DMA ILI9341 library and Extra fonts GFX Added DMA support for STM32F1xx, and extra check in line and rect funtions to avoid trying to draw a 0 width or 0 height line/rectangle, which would cause 0 bytes DMA transmission and hang in a loop. --- .../Adafruit_GFX.cpp} | 74 +-- .../Adafruit_GFX.h} | 12 +- .../Font16.c | 0 .../Font16.h | 0 .../Font32.c | 0 .../Font32.h | 0 .../Font64.c | 0 .../Font64.h | 0 .../Font7s.c | 0 .../Font7s.h | 0 .../Load_fonts.h | 0 .../README.txt | 0 .../glcdfont.c | 0 .../license.txt | 0 .../Adafruit_ILI9341/Adafruit_ILI9341.cpp | 592 ++++++++++-------- .../Adafruit_ILI9341/Adafruit_ILI9341.h | 42 +- STM32F1/libraries/Adafruit_ILI9341/License.h | 99 +++ STM32F1/libraries/Adafruit_ILI9341/README.txt | 18 +- .../TFT_Clock_Digital_ILI9341.ino | 10 +- .../TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino | 10 +- .../TFT_Rainbow_ILI9341.ino | 124 ++++ .../TFT_Show_Font_ILI9341.ino | 12 +- .../libraries/Adafruit_ILI9341_AS/README.txt | 23 - .../libraries/deprecatedAdafruit_ILI9341.zip | Bin 0 -> 23509 bytes 24 files changed, 638 insertions(+), 378 deletions(-) rename STM32F1/libraries/{Adafruit_GFX_AS/Adafruit_GFX_AS.cpp => Adafruit_GFX_Extended/Adafruit_GFX.cpp} (89%) rename STM32F1/libraries/{Adafruit_GFX_AS/Adafruit_GFX_AS.h => Adafruit_GFX_Extended/Adafruit_GFX.h} (92%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font16.c (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font16.h (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font32.c (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font32.h (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font64.c (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font64.h (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font7s.c (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Font7s.h (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/Load_fonts.h (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/README.txt (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/glcdfont.c (100%) rename STM32F1/libraries/{Adafruit_GFX_AS => Adafruit_GFX_Extended}/license.txt (100%) create mode 100644 STM32F1/libraries/Adafruit_ILI9341/License.h rename STM32F1/libraries/{Adafruit_ILI9341_AS => Adafruit_ILI9341}/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino (93%) rename STM32F1/libraries/{Adafruit_ILI9341_AS => Adafruit_ILI9341}/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino (94%) create mode 100644 STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Rainbow_ILI9341/TFT_Rainbow_ILI9341.ino rename STM32F1/libraries/{Adafruit_ILI9341_AS => Adafruit_ILI9341}/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino (94%) delete mode 100644 STM32F1/libraries/Adafruit_ILI9341_AS/README.txt create mode 100644 STM32F1/libraries/deprecatedAdafruit_ILI9341.zip diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp b/STM32F1/libraries/Adafruit_GFX_Extended/Adafruit_GFX.cpp similarity index 89% rename from STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp rename to STM32F1/libraries/Adafruit_GFX_Extended/Adafruit_GFX.cpp index 2c669e5..93e9090 100644 --- a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.cpp +++ b/STM32F1/libraries/Adafruit_GFX_Extended/Adafruit_GFX.cpp @@ -31,7 +31,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "Adafruit_GFX_AS.h" +#include "Adafruit_GFX.h" #ifdef LOAD_GLCD #include "glcdfont.c" @@ -59,7 +59,7 @@ POSSIBILITY OF SUCH DAMAGE. #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) #endif -Adafruit_GFX_AS::Adafruit_GFX_AS(int16_t w, int16_t h): +Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h): WIDTH(w), HEIGHT(h) { _width = WIDTH; @@ -72,7 +72,7 @@ Adafruit_GFX_AS::Adafruit_GFX_AS(int16_t w, int16_t h): } // Draw a circle outline -void Adafruit_GFX_AS::drawCircle(int16_t x0, int16_t y0, int16_t r, +void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) { int16_t f = 1 - r; int16_t ddF_x = 1; @@ -106,7 +106,7 @@ void Adafruit_GFX_AS::drawCircle(int16_t x0, int16_t y0, int16_t r, } } -void Adafruit_GFX_AS::drawCircleHelper( int16_t x0, int16_t y0, +void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color) { int16_t f = 1 - r; int16_t ddF_x = 1; @@ -142,14 +142,14 @@ void Adafruit_GFX_AS::drawCircleHelper( int16_t x0, int16_t y0, } } -void Adafruit_GFX_AS::fillCircle(int16_t x0, int16_t y0, int16_t r, +void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) { drawFastVLine(x0, y0-r, 2*r+1, color); fillCircleHelper(x0, y0, r, 3, 0, color); } // Used to do circles and roundrects -void Adafruit_GFX_AS::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, +void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color) { int16_t f = 1 - r; @@ -180,7 +180,7 @@ void Adafruit_GFX_AS::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, } // Bresenham's algorithm - thx wikpedia -void Adafruit_GFX_AS::drawLine(int16_t x0, int16_t y0, +void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) { int16_t steep = abs(y1 - y0) > abs(x1 - x0); @@ -222,7 +222,7 @@ void Adafruit_GFX_AS::drawLine(int16_t x0, int16_t y0, } // Draw a rectangle -void Adafruit_GFX_AS::drawRect(int16_t x, int16_t y, +void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { drawFastHLine(x, y, w, color); @@ -231,19 +231,19 @@ void Adafruit_GFX_AS::drawRect(int16_t x, int16_t y, drawFastVLine(x+w-1, y, h, color); } -void Adafruit_GFX_AS::drawFastVLine(int16_t x, int16_t y, +void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { // Update in subclasses if desired! drawLine(x, y, x, y+h-1, color); } -void Adafruit_GFX_AS::drawFastHLine(int16_t x, int16_t y, +void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { // Update in subclasses if desired! drawLine(x, y, x+w-1, y, color); } -void Adafruit_GFX_AS::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, +void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { // Update in subclasses if desired! for (int16_t i=x; i= 100 -size_t Adafruit_GFX_AS::write(uint8_t c) { +size_t Adafruit_GFX::write(uint8_t c) { //#else -//void Adafruit_GFX_AS::write(uint8_t c) { +//void Adafruit_GFX::write(uint8_t c) { //#endif if (c == '\n') { cursor_y += textsize*8; @@ -407,7 +407,7 @@ size_t Adafruit_GFX_AS::write(uint8_t c) { } // Draw a character -void Adafruit_GFX_AS::drawChar(int16_t x, int16_t y, unsigned char c, +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) { #ifdef LOAD_GLCD if((x >= _width) || // Clip right @@ -442,35 +442,35 @@ void Adafruit_GFX_AS::drawChar(int16_t x, int16_t y, unsigned char c, #endif } -void Adafruit_GFX_AS::setCursor(int16_t x, int16_t y) { +void Adafruit_GFX::setCursor(int16_t x, int16_t y) { cursor_x = x; cursor_y = y; } -void Adafruit_GFX_AS::setTextSize(uint8_t s) { +void Adafruit_GFX::setTextSize(uint8_t s) { textsize = (s > 0) ? s : 1; } -void Adafruit_GFX_AS::setTextColor(uint16_t c) { +void Adafruit_GFX::setTextColor(uint16_t c) { // For 'transparent' background, we'll set the bg // to the same as fg instead of using a flag textcolor = textbgcolor = c; } -void Adafruit_GFX_AS::setTextColor(uint16_t c, uint16_t b) { +void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) { textcolor = c; textbgcolor = b; } -void Adafruit_GFX_AS::setTextWrap(boolean w) { +void Adafruit_GFX::setTextWrap(boolean w) { wrap = w; } -uint8_t Adafruit_GFX_AS::getRotation(void) { +uint8_t Adafruit_GFX::getRotation(void) { return rotation; } -void Adafruit_GFX_AS::setRotation(uint8_t x) { +void Adafruit_GFX::setRotation(uint8_t x) { rotation = (x & 3); switch(rotation) { case 0: @@ -487,15 +487,15 @@ void Adafruit_GFX_AS::setRotation(uint8_t x) { } // Return the size of the display (per current rotation) -int16_t Adafruit_GFX_AS::width(void) { +int16_t Adafruit_GFX::width(void) { return _width; } -int16_t Adafruit_GFX_AS::height(void) { +int16_t Adafruit_GFX::height(void) { return _height; } -void Adafruit_GFX_AS::invertDisplay(boolean i) { +void Adafruit_GFX::invertDisplay(boolean i) { // Do nothing, must be subclassed if supported } @@ -503,7 +503,7 @@ void Adafruit_GFX_AS::invertDisplay(boolean i) { ** Function name: drawUnicode ** Descriptions: draw a unicode ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawUnicode(uint16_t uniCode, int16_t x, int16_t y, int16_t size) +int16_t Adafruit_GFX::drawUnicode(uint16_t uniCode, int16_t x, int16_t y, int16_t size) { if (size) uniCode -= 32; @@ -615,7 +615,7 @@ return (width+gap)*textsize; // x + ** Function name: drawNumber unsigned with size ** Descriptions: drawNumber ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawNumber(long long_num,int16_t poX, int16_t poY, int16_t size) +int16_t Adafruit_GFX::drawNumber(long long_num,int16_t poX, int16_t poY, int16_t size) { char tmp[10]; if (long_num < 0) sprintf(tmp, "%li", long_num); @@ -627,7 +627,7 @@ int16_t Adafruit_GFX_AS::drawNumber(long long_num,int16_t poX, int16_t poY, int1 ** Function name: drawChar ** Descriptions: draw char ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawChar(char c, int16_t x, int16_t y, int16_t size) +int16_t Adafruit_GFX::drawChar(char c, int16_t x, int16_t y, int16_t size) { return drawUnicode(c, x, y, size); } @@ -636,7 +636,7 @@ int16_t Adafruit_GFX_AS::drawChar(char c, int16_t x, int16_t y, int16_t size) ** Function name: drawString ** Descriptions: draw string ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawString(char *string, int16_t poX, int16_t poY, int16_t size) +int16_t Adafruit_GFX::drawString(char *string, int16_t poX, int16_t poY, int16_t size) { int16_t sumX = 0; @@ -654,7 +654,7 @@ int16_t Adafruit_GFX_AS::drawString(char *string, int16_t poX, int16_t poY, int1 ** Function name: drawCentreString ** Descriptions: draw string across centre ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawCentreString(char *string, int16_t dX, int16_t poY, int16_t size) +int16_t Adafruit_GFX::drawCentreString(char *string, int16_t dX, int16_t poY, int16_t size) { int16_t sumX = 0; int16_t len = 0; @@ -703,7 +703,7 @@ int16_t Adafruit_GFX_AS::drawCentreString(char *string, int16_t dX, int16_t poY, ** Function name: drawRightString ** Descriptions: draw string right justified ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawRightString(char *string, int16_t dX, int16_t poY, int16_t size) +int16_t Adafruit_GFX::drawRightString(char *string, int16_t dX, int16_t poY, int16_t size) { int16_t sumX = 0; int16_t len = 0; @@ -754,7 +754,7 @@ int16_t Adafruit_GFX_AS::drawRightString(char *string, int16_t dX, int16_t poY, ** Function name: drawFloat ** Descriptions: drawFloat ***************************************************************************************/ -int16_t Adafruit_GFX_AS::drawFloat(float floatNumber, int16_t decimal, int16_t poX, int16_t poY, int16_t size) +int16_t Adafruit_GFX::drawFloat(float floatNumber, int16_t decimal, int16_t poX, int16_t poY, int16_t size) { unsigned long temp=0; float decy=0.0; diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h b/STM32F1/libraries/Adafruit_GFX_Extended/Adafruit_GFX.h similarity index 92% rename from STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h rename to STM32F1/libraries/Adafruit_GFX_Extended/Adafruit_GFX.h index 42c9919..974c47c 100644 --- a/STM32F1/libraries/Adafruit_GFX_AS/Adafruit_GFX_AS.h +++ b/STM32F1/libraries/Adafruit_GFX_Extended/Adafruit_GFX.h @@ -1,5 +1,5 @@ -#ifndef _ADAFRUIT_GFX_AS_H -#define _ADAFRUIT_GFX_AS_H +#ifndef _ADAFRUIT_GFX_H +#define _ADAFRUIT_GFX_H #include "Load_fonts.h" @@ -12,11 +12,11 @@ #define swap(a, b) { int16_t t = a; a = b; b = t; } -class Adafruit_GFX_AS : public Print { +class Adafruit_GFX : public Print { public: - Adafruit_GFX_AS(int16_t w, int16_t h); // Constructor + Adafruit_GFX(int16_t w, int16_t h); // Constructor // This MUST be defined by the subclass: virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; @@ -32,7 +32,7 @@ class Adafruit_GFX_AS : public Print { fillScreen(uint16_t color), invertDisplay(boolean i); - // These exist only with Adafruit_GFX_AS (no subclass overrides) + // These exist only with Adafruit_GFX (no subclass overrides) void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color), drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, @@ -94,4 +94,4 @@ class Adafruit_GFX_AS : public Print { wrap; // If set, 'wrap' text at right edge of display }; -#endif // _ADAFRUIT_GFX_AS_H +#endif // _ADAFRUIT_GFX_H diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font16.c b/STM32F1/libraries/Adafruit_GFX_Extended/Font16.c similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font16.c rename to STM32F1/libraries/Adafruit_GFX_Extended/Font16.c diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font16.h b/STM32F1/libraries/Adafruit_GFX_Extended/Font16.h similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font16.h rename to STM32F1/libraries/Adafruit_GFX_Extended/Font16.h diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font32.c b/STM32F1/libraries/Adafruit_GFX_Extended/Font32.c similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font32.c rename to STM32F1/libraries/Adafruit_GFX_Extended/Font32.c diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font32.h b/STM32F1/libraries/Adafruit_GFX_Extended/Font32.h similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font32.h rename to STM32F1/libraries/Adafruit_GFX_Extended/Font32.h diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font64.c b/STM32F1/libraries/Adafruit_GFX_Extended/Font64.c similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font64.c rename to STM32F1/libraries/Adafruit_GFX_Extended/Font64.c diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font64.h b/STM32F1/libraries/Adafruit_GFX_Extended/Font64.h similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font64.h rename to STM32F1/libraries/Adafruit_GFX_Extended/Font64.h diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font7s.c b/STM32F1/libraries/Adafruit_GFX_Extended/Font7s.c similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font7s.c rename to STM32F1/libraries/Adafruit_GFX_Extended/Font7s.c diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Font7s.h b/STM32F1/libraries/Adafruit_GFX_Extended/Font7s.h similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Font7s.h rename to STM32F1/libraries/Adafruit_GFX_Extended/Font7s.h diff --git a/STM32F1/libraries/Adafruit_GFX_AS/Load_fonts.h b/STM32F1/libraries/Adafruit_GFX_Extended/Load_fonts.h similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/Load_fonts.h rename to STM32F1/libraries/Adafruit_GFX_Extended/Load_fonts.h diff --git a/STM32F1/libraries/Adafruit_GFX_AS/README.txt b/STM32F1/libraries/Adafruit_GFX_Extended/README.txt similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/README.txt rename to STM32F1/libraries/Adafruit_GFX_Extended/README.txt diff --git a/STM32F1/libraries/Adafruit_GFX_AS/glcdfont.c b/STM32F1/libraries/Adafruit_GFX_Extended/glcdfont.c similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/glcdfont.c rename to STM32F1/libraries/Adafruit_GFX_Extended/glcdfont.c diff --git a/STM32F1/libraries/Adafruit_GFX_AS/license.txt b/STM32F1/libraries/Adafruit_GFX_Extended/license.txt similarity index 100% rename from STM32F1/libraries/Adafruit_GFX_AS/license.txt rename to STM32F1/libraries/Adafruit_GFX_Extended/license.txt diff --git a/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp b/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp index 2f6e1c7..261dd20 100644 --- a/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp +++ b/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.cpp @@ -1,28 +1,20 @@ -/*************************************************** - This is our library for the Adafruit ILI9341 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - 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 - ****************************************************/ - +/* +See rights and use declaration in License.h +This library has been modified for the Maple Mini +*/ #include "Adafruit_ILI9341.h" #include #include +#include #include "pins_arduino.h" #include "wiring_private.h" -#include +#include // Using library SPI in folder: D:\Documents\Arduino\hardware\STM32\STM32F1XX\libraries\SPI + +volatile bool dma1_ch3_Active = false; // Constructor when using software SPI. All output pins are configurable. Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t mosi, - int8_t sclk, int8_t rst, int8_t miso) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { + int8_t sclk, int8_t rst, int8_t miso) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { _cs = cs; _dc = dc; _mosi = mosi; @@ -43,36 +35,43 @@ Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) : Adafruit_ _mosi = _sclk = 0; } +inline void DMA1_CH3_Event() { + dma1_ch3_Active = 0; + dma_disable(DMA1, DMA_CH3); +} + void Adafruit_ILI9341::spiwrite(uint8_t c) { //Serial.print("0x"); Serial.print(c, HEX); Serial.print(", "); - if (hwSPI) { + if (hwSPI) + { #if defined (__AVR__) - uint8_t backupSPCR = SPCR; + uint8_t backupSPCR = SPCR; SPCR = mySPCR; SPDR = c; - while(!(SPSR & _BV(SPIF))); + while (!(SPSR & _BV(SPIF))); SPCR = backupSPCR; #elif defined(TEENSYDUINO) SPI.transfer(c); #elif defined (__STM32F1__) - SPI.write(c);// Faster than transfer as we don't need to read + SPI.transfer(c); #elif defined (__arm__) SPI.setClockDivider(11); // 8-ish MHz (full! speed!) SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); SPI.transfer(c); + #endif } else { // Fast SPI bitbang swiped from LPD8806 library - for(uint8_t bit = 0x80; bit; bit >>= 1) { - if(c & bit) { - //digitalWrite(_mosi, HIGH); - *mosiport |= mosipinmask; + for (uint8_t bit = 0x80; bit; bit >>= 1) { + if (c & bit) { + //digitalWrite(_mosi, HIGH); + *mosiport |= mosipinmask; } else { - //digitalWrite(_mosi, LOW); - *mosiport &= ~mosipinmask; + //digitalWrite(_mosi, LOW); + *mosiport &= ~mosipinmask; } //digitalWrite(_sclk, HIGH); *clkport |= clkpinmask; @@ -85,18 +84,32 @@ void Adafruit_ILI9341::spiwrite(uint8_t c) { void Adafruit_ILI9341::writecommand(uint8_t c) { *dcport &= ~dcpinmask; + //digitalWrite(_dc, LOW); + //*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true + //digitalWrite(_sclk, LOW); *csport &= ~cspinmask; - SPI.write(c); + //digitalWrite(_cs, LOW); + + spiwrite(c); + *csport |= cspinmask; + //digitalWrite(_cs, HIGH); } void Adafruit_ILI9341::writedata(uint8_t c) { *dcport |= dcpinmask; + //digitalWrite(_dc, HIGH); + //*clkport &= ~clkpinmask; // clkport is a NULL pointer when hwSPI==true + //digitalWrite(_sclk, LOW); *csport &= ~cspinmask; - SPI.write(c); + //digitalWrite(_cs, LOW); + + spiwrite(c); + + //digitalWrite(_cs, HIGH); *csport |= cspinmask; -} +} // If the SPI library has transaction support, these functions // establish settings and protect from interference from other @@ -130,29 +143,22 @@ void Adafruit_ILI9341::commandList(uint8_t *addr) { uint8_t numCommands, numArgs; uint16_t ms; - *dcport |= dcpinmask; - *csport &= ~cspinmask; - - - - numCommands = pgm_read_byte(addr++); // Number of commands to follow - while(numCommands--) { // For each command... + while (numCommands--) { // For each command... writecommand(pgm_read_byte(addr++)); // Read, issue command numArgs = pgm_read_byte(addr++); // Number of args to follow ms = numArgs & DELAY; // If hibit set, delay follows args numArgs &= ~DELAY; // Mask out delay bit - while(numArgs--) { // For each argument... - SPI.write(pgm_read_byte(addr++)); // Read, issue argument + while (numArgs--) { // For each argument... + writedata(pgm_read_byte(addr++)); // Read, issue argument } - if(ms) { + if (ms) { ms = pgm_read_byte(addr++); // Read post-command delay time (ms) - if(ms == 255) ms = 500; // If 255, delay for 500 ms + if (ms == 255) ms = 500; // If 255, delay for 500 ms delay(ms); } } - *csport |= cspinmask; } @@ -169,23 +175,36 @@ void Adafruit_ILI9341::begin(void) { dcport = portOutputRegister(digitalPinToPort(_dc)); dcpinmask = digitalPinToBitMask(_dc); - if(hwSPI) { // Using hardware SPI + if (hwSPI) { // Using hardware SPI #if defined (__AVR__) SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!) SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); mySPCR = SPCR; -#elif defined(TEENSYDUINO) || defined (__STM32F1__) +#elif defined(TEENSYDUINO) SPI.begin(); SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!) SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); +#elif defined (__STM32F1__) + SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV2); + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + // DMA setup stuff. We use a line buffer and usa DMA for filling lines and blocks. + spi_tx_dma_enable(SPI1); + dma_init(DMA1); + dma_attach_interrupt(DMA1, DMA_CH3, DMA1_CH3_Event); + dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, + lineBuffer, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT)); + + #elif defined (__arm__) - SPI.begin(); - SPI.setClockDivider(11); // 8-ish MHz (full! speed!) - SPI.setBitOrder(MSBFIRST); - SPI.setDataMode(SPI_MODE0); + SPI.begin(); + SPI.setClockDivider(11); // 8-ish MHz (full! speed!) + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); #endif } else { pinMode(_sclk, OUTPUT); @@ -209,139 +228,148 @@ void Adafruit_ILI9341::begin(void) { delay(150); } - + /* + uint8_t x = readcommand8(ILI9341_RDMODE); + Serial.print("\nDisplay Power Mode: 0x"); Serial.println(x, HEX); + x = readcommand8(ILI9341_RDMADCTL); + Serial.print("\nMADCTL Mode: 0x"); Serial.println(x, HEX); + x = readcommand8(ILI9341_RDPIXFMT); + Serial.print("\nPixel Format: 0x"); Serial.println(x, HEX); + x = readcommand8(ILI9341_RDIMGFMT); + Serial.print("\nImage Format: 0x"); Serial.println(x, HEX); + x = readcommand8(ILI9341_RDSELFDIAG); + Serial.print("\nSelf Diagnostic: 0x"); Serial.println(x, HEX); + */ + //if(cmdList) commandList(cmdList); + if (hwSPI) spi_begin(); writecommand(0xEF); writedata(0x03); writedata(0x80); writedata(0x02); - writecommand(0xCF); - writedata(0x00); - writedata(0XC1); - writedata(0X30); + writecommand(0xCF); + writedata(0x00); + writedata(0XC1); + writedata(0X30); - writecommand(0xED); - writedata(0x64); - writedata(0x03); - writedata(0X12); - writedata(0X81); - - writecommand(0xE8); - writedata(0x85); - writedata(0x00); - writedata(0x78); + writecommand(0xED); + writedata(0x64); + writedata(0x03); + writedata(0X12); + writedata(0X81); - writecommand(0xCB); - writedata(0x39); - writedata(0x2C); - writedata(0x00); - writedata(0x34); - writedata(0x02); - - writecommand(0xF7); - writedata(0x20); + writecommand(0xE8); + writedata(0x85); + writedata(0x00); + writedata(0x78); - writecommand(0xEA); - writedata(0x00); - writedata(0x00); - - writecommand(ILI9341_PWCTR1); //Power control - writedata(0x23); //VRH[5:0] - - writecommand(ILI9341_PWCTR2); //Power control - writedata(0x10); //SAP[2:0];BT[3:0] - - writecommand(ILI9341_VMCTR1); //VCM control - writedata(0x3e); //对比度调节 - writedata(0x28); - - writecommand(ILI9341_VMCTR2); //VCM control2 + writecommand(0xCB); + writedata(0x39); + writedata(0x2C); + writedata(0x00); + writedata(0x34); + writedata(0x02); + + writecommand(0xF7); + writedata(0x20); + + writecommand(0xEA); + writedata(0x00); + writedata(0x00); + + writecommand(ILI9341_PWCTR1); //Power control + writedata(0x23); //VRH[5:0] + + writecommand(ILI9341_PWCTR2); //Power control + writedata(0x10); //SAP[2:0];BT[3:0] + + writecommand(ILI9341_VMCTR1); //VCM control + writedata(0x3e); //锟皆比度碉拷锟斤拷 + writedata(0x28); + + writecommand(ILI9341_VMCTR2); //VCM control2 writedata(0x86); //-- - - writecommand(ILI9341_MADCTL); // Memory Access Control + + writecommand(ILI9341_MADCTL); // Memory Access Control writedata(0x48); - writecommand(ILI9341_PIXFMT); - writedata(0x55); - - writecommand(ILI9341_FRMCTR1); - writedata(0x00); - writedata(0x18); - - writecommand(ILI9341_DFUNCTR); // Display Function Control - writedata(0x08); - writedata(0x82); - writedata(0x27); - - writecommand(0xF2); // 3Gamma Function Disable - writedata(0x00); - - writecommand(ILI9341_GAMMASET); //Gamma curve selected - writedata(0x01); - - writecommand(ILI9341_GMCTRP1); //Set Gamma - writedata(0x0F); - writedata(0x31); - writedata(0x2B); - writedata(0x0C); - writedata(0x0E); - writedata(0x08); - writedata(0x4E); - writedata(0xF1); - writedata(0x37); - writedata(0x07); - writedata(0x10); - writedata(0x03); - writedata(0x0E); - writedata(0x09); - writedata(0x00); - - writecommand(ILI9341_GMCTRN1); //Set Gamma - writedata(0x00); - writedata(0x0E); - writedata(0x14); - writedata(0x03); - writedata(0x11); - writedata(0x07); - writedata(0x31); - writedata(0xC1); - writedata(0x48); - writedata(0x08); - writedata(0x0F); - writedata(0x0C); - writedata(0x31); - writedata(0x36); - writedata(0x0F); + writecommand(ILI9341_PIXFMT); + writedata(0x55); - writecommand(ILI9341_SLPOUT); //Exit Sleep + writecommand(ILI9341_FRMCTR1); + writedata(0x00); + writedata(0x18); + + writecommand(ILI9341_DFUNCTR); // Display Function Control + writedata(0x08); + writedata(0x82); + writedata(0x27); + + writecommand(0xF2); // 3Gamma Function Disable + writedata(0x00); + + writecommand(ILI9341_GAMMASET); //Gamma curve selected + writedata(0x01); + + writecommand(ILI9341_GMCTRP1); //Set Gamma + writedata(0x0F); + writedata(0x31); + writedata(0x2B); + writedata(0x0C); + writedata(0x0E); + writedata(0x08); + writedata(0x4E); + writedata(0xF1); + writedata(0x37); + writedata(0x07); + writedata(0x10); + writedata(0x03); + writedata(0x0E); + writedata(0x09); + writedata(0x00); + + writecommand(ILI9341_GMCTRN1); //Set Gamma + writedata(0x00); + writedata(0x0E); + writedata(0x14); + writedata(0x03); + writedata(0x11); + writedata(0x07); + writedata(0x31); + writedata(0xC1); + writedata(0x48); + writedata(0x08); + writedata(0x0F); + writedata(0x0C); + writedata(0x31); + writedata(0x36); + writedata(0x0F); + + writecommand(ILI9341_SLPOUT); //Exit Sleep if (hwSPI) spi_end(); - delay(120); + delay(120); if (hwSPI) spi_begin(); - writecommand(ILI9341_DISPON); //Display on + writecommand(ILI9341_DISPON); //Display on if (hwSPI) spi_end(); } void Adafruit_ILI9341::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, - uint16_t y1) { + uint16_t y1) { writecommand(ILI9341_CASET); // Column addr set - *dcport |= dcpinmask; - *csport &= ~cspinmask; - SPI.write(x0 >> 8); - SPI.write(x0 & 0xFF); // XSTART - SPI.write(x1 >> 8); - SPI.write(x1 & 0xFF); // XEND + writedata(x0 >> 8); + writedata(x0 & 0xFF); // XSTART + writedata(x1 >> 8); + writedata(x1 & 0xFF); // XEND writecommand(ILI9341_PASET); // Row addr set - *dcport |= dcpinmask; - *csport &= ~cspinmask; - SPI.write(y0>>8); - SPI.write(y0); // YSTART - SPI.write(y1>>8); - SPI.write(y1); // YEND + writedata(y0 >> 8); + writedata(y0); // YSTART + writedata(y1 >> 8); + writedata(y1); // YEND writecommand(ILI9341_RAMWR); // write to RAM } @@ -349,13 +377,13 @@ void Adafruit_ILI9341::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, void Adafruit_ILI9341::pushColor(uint16_t color) { if (hwSPI) spi_begin(); - + //digitalWrite(_dc, HIGH); *dcport |= dcpinmask; - + //digitalWrite(_cs, LOW); *csport &= ~cspinmask; - SPI.write(color >> 8); - SPI.write(color); + spiwrite(color >> 8); + spiwrite(color); *csport |= cspinmask; //digitalWrite(_cs, HIGH); @@ -364,67 +392,102 @@ void Adafruit_ILI9341::pushColor(uint16_t color) { void Adafruit_ILI9341::drawPixel(int16_t x, int16_t y, uint16_t color) { - if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; + if ((x < 0) || (x >= _width) || (y < 0) || (y >= _height)) return; if (hwSPI) spi_begin(); - setAddrWindow(x,y,x+1,y+1); + setAddrWindow(x, y, x + 1, y + 1); + //digitalWrite(_dc, HIGH); *dcport |= dcpinmask; + //digitalWrite(_cs, LOW); *csport &= ~cspinmask; - SPI.write(color >> 8); - SPI.write(color); + spiwrite(color >> 8); + spiwrite(color); *csport |= cspinmask; + //digitalWrite(_cs, HIGH); if (hwSPI) spi_end(); } void Adafruit_ILI9341::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { + uint16_t color) { // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; + if ((x >= _width) || (y >= _height || h < 1)) return; + + if ((y + h - 1) >= _height) + h = _height - y; + + // if (hwSPI) spi_begin(); + setAddrWindow(x, y, x, y + h - 1); - if((y+h-1) >= _height) - { - h = _height-y; - } - - if (hwSPI) spi_begin(); - setAddrWindow(x, y, x, y+h-1); uint8_t hi = color >> 8, lo = color; + *dcport |= dcpinmask; + //digitalWrite(_dc, HIGH); *csport &= ~cspinmask; - - while (h--) + //digitalWrite(_cs, LOW); + +#if defined (__STM32F1__) + for (int i = 0; i < (h * 2) - 1 ; i = i + 2) { - SPI.write(hi); - SPI.write(lo); + lineBuffer[i] = hi; + lineBuffer[i + 1] = lo; } - *csport |= cspinmask; + dma_set_num_transfers(DMA1, DMA_CH3, h * 2); // 2 bytes per pixel + dma1_ch3_Active = true; + dma_enable(DMA1, DMA_CH3); + while (dma1_ch3_Active); - if (hwSPI) spi_end(); + #else + while (h--) { + spiwrite(hi); + spiwrite(lo); + } +#endif + *csport |= cspinmask; + //digitalWrite(_cs, HIGH); + // if (hwSPI) spi_end(); } void Adafruit_ILI9341::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { + uint16_t color) { + // Rudimentary clipping - if((x >= _width) || (y >= _height)) return; - if((x+w-1) >= _width) w = _width-x; + if ((x >= _width) || (y >= _height || w < 1)) return; + if ((x + w - 1) >= _width) w = _width - x; if (hwSPI) spi_begin(); - setAddrWindow(x, y, x+w-1, y); + setAddrWindow(x, y, x + w - 1, y); uint8_t hi = color >> 8, lo = color; *dcport |= dcpinmask; *csport &= ~cspinmask; - while (w--) { - SPI.write(hi); - SPI.write(lo); + //digitalWrite(_dc, HIGH); + //digitalWrite(_cs, LOW); +#if defined (__STM32F1__) + + for (int i = 0; i < (w * 2) - 1 ; i = i + 2) + { + lineBuffer[i] = hi; + lineBuffer[i + 1] = lo; } + dma_set_num_transfers(DMA1, DMA_CH3, w * 2); // 2 bytes per pixel + dma1_ch3_Active = true; + dma_enable(DMA1, DMA_CH3); + while (dma1_ch3_Active) delayMicroseconds(1); + +#else + while (w--) { + spiwrite(hi); + spiwrite(lo); + } +#endif *csport |= cspinmask; + //digitalWrite(_cs, HIGH); if (hwSPI) spi_end(); } @@ -434,21 +497,42 @@ void Adafruit_ILI9341::fillScreen(uint16_t color) { // fill a rectangle void Adafruit_ILI9341::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - int numPixels; + uint16_t color) { + // rudimentary clipping (drawChar w/big text requires this) - if((x >= _width) || (y >= _height)) return; - if((x + w - 1) >= _width) w = _width - x; - if((y + h - 1) >= _height) h = _height - y; + if ((x >= _width) || (y >= _height || h < 1 || w < 1)) return; + if ((x + w - 1) >= _width) w = _width - x; + if ((y + h - 1) >= _height) h = _height - y; if (hwSPI) spi_begin(); - setAddrWindow(x, y, x+w-1, y+h-1); + setAddrWindow(x, y, x + w - 1, y + h - 1); uint8_t hi = color >> 8, lo = color; *dcport |= dcpinmask; + //digitalWrite(_dc, HIGH); *csport &= ~cspinmask; + //digitalWrite(_cs, LOW); +#if defined (__STM32F1__) + //moved this loop outside as we can fill the buffer once and send it multiple times. + for (int i = 0; i < (w * 2) - 1 ; i = i + 2) + { + lineBuffer[i] = hi; + lineBuffer[i + 1] = lo; + } + + for (y = h; y > 0; y--) { + // for(x=w; x>0; x--) { + // spiwrite(hi); + // spiwrite(lo); + // } + dma_set_num_transfers(DMA1, DMA_CH3, w * 2); // 2 bytes per pixel + dma1_ch3_Active = true; + dma_enable(DMA1, DMA_CH3); + while (dma1_ch3_Active) delayMicroseconds(1); + } +#else for(y=h; y>0; y--) { for(x=w; x>0; x--) @@ -457,9 +541,11 @@ void Adafruit_ILI9341::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, SPI.write(lo); } } - - if (hwSPI) spi_end(); +#endif + + //digitalWrite(_cs, HIGH); *csport |= cspinmask; + if (hwSPI) spi_end(); } @@ -483,26 +569,26 @@ void Adafruit_ILI9341::setRotation(uint8_t m) { writecommand(ILI9341_MADCTL); rotation = m % 4; // can't be higher than 3 switch (rotation) { - case 0: - writedata(MADCTL_MX | MADCTL_BGR); - _width = ILI9341_TFTWIDTH; - _height = ILI9341_TFTHEIGHT; - break; - case 1: - writedata(MADCTL_MV | MADCTL_BGR); - _width = ILI9341_TFTHEIGHT; - _height = ILI9341_TFTWIDTH; - break; - case 2: - writedata(MADCTL_MY | MADCTL_BGR); - _width = ILI9341_TFTWIDTH; - _height = ILI9341_TFTHEIGHT; - break; - case 3: - writedata(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); - _width = ILI9341_TFTHEIGHT; - _height = ILI9341_TFTWIDTH; - break; + case 0: + writedata(MADCTL_MX | MADCTL_BGR); + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + break; + case 1: + writedata(MADCTL_MV | MADCTL_BGR); + _width = ILI9341_TFTHEIGHT; + _height = ILI9341_TFTWIDTH; + break; + case 2: + writedata(MADCTL_MY | MADCTL_BGR); + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + break; + case 3: + writedata(MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); + _width = ILI9341_TFTHEIGHT; + _height = ILI9341_TFTWIDTH; + break; } if (hwSPI) spi_end(); } @@ -526,10 +612,12 @@ uint8_t Adafruit_ILI9341::spiread(void) { uint8_t backupSPCR = SPCR; SPCR = mySPCR; SPDR = 0x00; - while(!(SPSR & _BV(SPIF))); + while (!(SPSR & _BV(SPIF))); r = SPDR; SPCR = backupSPCR; -#elif defined(TEENSYDUINO) || defined (__STM32F1__) +#elif defined(TEENSYDUINO) + r = SPI.transfer(0x00); +#elif defined (__STM32F1__) r = SPI.transfer(0x00); #elif defined (__arm__) SPI.setClockDivider(11); // 8-ish MHz (full! speed!) @@ -539,59 +627,59 @@ uint8_t Adafruit_ILI9341::spiread(void) { #endif } else { - for (uint8_t i=0; i<8; i++) { + for (uint8_t i = 0; i < 8; i++) { digitalWrite(_sclk, LOW); digitalWrite(_sclk, HIGH); r <<= 1; if (digitalRead(_miso)) - r |= 0x1; + r |= 0x1; } } //Serial.print("read: 0x"); Serial.print(r, HEX); - + return r; } - uint8_t Adafruit_ILI9341::readdata(void) { - digitalWrite(_dc, HIGH); - digitalWrite(_cs, LOW); - uint8_t r = spiread(); - digitalWrite(_cs, HIGH); - - return r; +uint8_t Adafruit_ILI9341::readdata(void) { + digitalWrite(_dc, HIGH); + digitalWrite(_cs, LOW); + uint8_t r = spiread(); + digitalWrite(_cs, HIGH); + + return r; } - + uint8_t Adafruit_ILI9341::readcommand8(uint8_t c, uint8_t index) { - if (hwSPI) spi_begin(); - digitalWrite(_dc, LOW); // command - digitalWrite(_cs, LOW); - SPI.write(0xD9); // woo sekret command? - digitalWrite(_dc, HIGH); // data - SPI.write(0x10 + index); - digitalWrite(_cs, HIGH); + if (hwSPI) spi_begin(); + digitalWrite(_dc, LOW); // command + digitalWrite(_cs, LOW); + spiwrite(0xD9); // woo sekret command? + digitalWrite(_dc, HIGH); // data + spiwrite(0x10 + index); + digitalWrite(_cs, HIGH); - digitalWrite(_dc, LOW); - digitalWrite(_sclk, LOW); - digitalWrite(_cs, LOW); - SPI.write(c); - - digitalWrite(_dc, HIGH); - uint8_t r = spiread(); - digitalWrite(_cs, HIGH); - if (hwSPI) spi_end(); - return r; + digitalWrite(_dc, LOW); + digitalWrite(_sclk, LOW); + digitalWrite(_cs, LOW); + spiwrite(c); + + digitalWrite(_dc, HIGH); + uint8_t r = spiread(); + digitalWrite(_cs, HIGH); + if (hwSPI) spi_end(); + return r; } - + /* uint16_t Adafruit_ILI9341::readcommand16(uint8_t c) { digitalWrite(_dc, LOW); if (_cs) digitalWrite(_cs, LOW); - + spiwrite(c); pinMode(_sid, INPUT); // input! uint16_t r = spiread(); @@ -599,21 +687,21 @@ uint8_t Adafruit_ILI9341::readcommand8(uint8_t c, uint8_t index) { r |= spiread(); if (_cs) digitalWrite(_cs, HIGH); - + pinMode(_sid, OUTPUT); // back to output return r; } - + uint32_t Adafruit_ILI9341::readcommand32(uint8_t c) { digitalWrite(_dc, LOW); if (_cs) digitalWrite(_cs, LOW); spiwrite(c); pinMode(_sid, INPUT); // input! - + dummyclock(); dummyclock(); - + uint32_t r = spiread(); r <<= 8; r |= spiread(); @@ -623,9 +711,9 @@ uint8_t Adafruit_ILI9341::readcommand8(uint8_t c, uint8_t index) { r |= spiread(); if (_cs) digitalWrite(_cs, HIGH); - + pinMode(_sid, OUTPUT); // back to output return r; } - + */ diff --git a/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h b/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h index 1ce359a..591612b 100644 --- a/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h +++ b/STM32F1/libraries/Adafruit_ILI9341/Adafruit_ILI9341.h @@ -1,31 +1,16 @@ -/*************************************************** - This is our library for the Adafruit ILI9341 Breakout and Shield - ----> http://www.adafruit.com/products/1651 - - 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 - ****************************************************/ +/* +See rights and use declaration in License.h +This library has been modified for the Maple Mini +*/ #ifndef _ADAFRUIT_ILI9341H_ #define _ADAFRUIT_ILI9341H_ -#if ARDUINO >= 100 - #include "Arduino.h" - #include "Print.h" -#else - #include "WProgram.h" -#endif -#include +#include "Arduino.h" +#include "Print.h" +#include "Adafruit_GFX.h" #include - #define ILI9341_TFTWIDTH 240 #define ILI9341_TFTHEIGHT 320 @@ -114,7 +99,7 @@ class Adafruit_ILI9341 : public Adafruit_GFX { Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, int8_t _RST, int8_t _MISO); Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _RST = -1); - + void begin(void), setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1), pushColor(uint16_t color), @@ -143,22 +128,23 @@ class Adafruit_ILI9341 : public Adafruit_GFX { commandList(uint8_t *addr); uint8_t spiread(void); + private: uint8_t tabcolor; +volatile byte lineBuffer[640]; boolean hwSPI; -#if defined (__STM32F1__) -#define RwReg uint32 -#endif - - #if defined (__AVR__) || defined(TEENSYDUINO) uint8_t mySPCR; volatile uint8_t *mosiport, *clkport, *dcport, *rsport, *csport; int8_t _cs, _dc, _rst, _mosi, _miso, _sclk; uint8_t mosipinmask, clkpinmask, cspinmask, dcpinmask; +#elif defined (__STM32F1__) + volatile uint32 *mosiport, *clkport, *dcport, *rsport, *csport; + uint32_t _cs, _dc, _rst, _mosi, _miso, _sclk; + uint32_t mosipinmask, clkpinmask, cspinmask, dcpinmask; #elif defined (__arm__) volatile RwReg *mosiport, *clkport, *dcport, *rsport, *csport; uint32_t _cs, _dc, _rst, _mosi, _miso, _sclk; diff --git a/STM32F1/libraries/Adafruit_ILI9341/License.h b/STM32F1/libraries/Adafruit_ILI9341/License.h new file mode 100644 index 0000000..b7da6b9 --- /dev/null +++ b/STM32F1/libraries/Adafruit_ILI9341/License.h @@ -0,0 +1,99 @@ +// License.h +// All tab licenses are here +// This library was modified to support DMA in Maple Mini by Victor Perez in 03/17/2015 + +/*************************************************** + This is our GFX example for the Adafruit ILI9341 Breakout and Shield + ----> http://www.adafruit.com/products/1651 + 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) +/* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/*************************************************** + This is our library for the Adafruit ILI9341 Breakout and Shield + ----> http://www.adafruit.com/products/1651 + + 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 + ****************************************************/ + +/* +Roughly based on Adafruit example sketch: "parsing" +Utilizes the (modified) Adafruit_GPS library https://github.com/adafruit/Adafruit-GPS-Library +20131204: GPS TimeDate with Temperature + Heavily mucked by M. Ray Burnette to simply use (most) any dumb serial TTL GPS for time-date + Tested with unit#28146 Parallax module @4800 BAUD http://www.abra-electronics.com/products/28146-Parallax-GPS-Receiver-Module.html + Tested with uBlox and external antenna @9600 BAUD http://www.ebay.com/itm/390647042336 + Tested with uBlox and internal antenna @9600 BAUD http://www.ebay.com/itm/181219728986 + +*/ +/* +SoftwareSerial.h (formerly NewSoftSerial.h) - +Multi-instance software serial library for Arduino/Wiring +-- Interrupt-driven receive and other improvements by ladyada + (http://ladyada.net) +-- Tuning, circular buffer, derivation from class Print/Stream, + multi-instance support, porting to 8MHz processors, + various optimizations, PROGMEM delay tables, inverse logic and + direct port writing by Mikal Hart (http://www.arduiniana.org) +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) +-- 20MHz processor support by Garrett Mace (http://www.macetech.com) +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +The latest version of this library can always be found at +http://arduiniana.org. +*/ + diff --git a/STM32F1/libraries/Adafruit_ILI9341/README.txt b/STM32F1/libraries/Adafruit_ILI9341/README.txt index 58d2b57..6fa8ba8 100644 --- a/STM32F1/libraries/Adafruit_ILI9341/README.txt +++ b/STM32F1/libraries/Adafruit_ILI9341/README.txt @@ -1,19 +1,5 @@ -This library is based on the Adafruit ILI9341 (see original Adafuit text description below) - - -It has minor modifications to support STM32 and also one small change to use spi.write(byte) instead of spi.transfer(byte) as this gave -a useful speed improvement. - -It has been tested with standard ILI9341 from various suppliers e.g on eBay - -This library requires the Adafruit GFC library, https://github.com/adafruit/Adafruit-GFX-Library - -An addition example stm32_graphicstest has been added to show how to configure for stm32 - which uses hardware SPI and hence its not possible to -set the SCK MISO and MOSI pins. - -_________________________ Original text from Adafruit ____________________________________________ - - +It has minor modifications to support STM32. It has been tested with the Maple Mini. +Further modifications to support DMA transfers in the STM32F1xx by Victor Perez 3/17/2015 This is a library for the Adafruit ILI9341 display products diff --git a/STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino similarity index 93% rename from STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino rename to STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino index 1be8715..286bd44 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino +++ b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Clock_Digital_ILI9341/TFT_Clock_Digital_ILI9341.ino @@ -31,19 +31,19 @@ code color */ // These are the connections for the UNO -#define sclk 6 // Don't change -#define mosi 4 // Don't change +//#define sclk 6 // Don't change +//#define mosi 4 // Don't change #define cs 8 #define dc 10 #define rst 9 // you can also connect this to the Arduino reset -#include // Core graphics library -#include // Hardware-specific library +#include // Core graphics library +#include // Hardware-specific library #include #define ILI9341_GREY 0x5AEB -Adafruit_ILI9341_AS tft = Adafruit_ILI9341_AS(cs, dc, rst); // Invoke custom library +Adafruit_ILI9341 tft = Adafruit_ILI9341(cs, dc, rst); // Invoke custom library uint32_t targetTime = 0; // for next 1 second timeout uint8_t hh=conv2d(__TIME__), mm=conv2d(__TIME__+3), ss=conv2d(__TIME__+6); // Get H, M, S from compile time diff --git a/STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino similarity index 94% rename from STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino rename to STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino index 6dd9e63..ada0fb4 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino +++ b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Clock_ILI9341/TFT_Clock_ILI9341.ino @@ -11,19 +11,19 @@ Updated by Alan Senior 18/1/2015 */ -#define sclk 6 // Don't change -#define mosi 4 // Don't change +//#define sclk 6 // Don't change +//#define mosi 4 // Don't change #define cs 8 #define dc 10 #define rst 9 // you can also connect this to the Arduino reset -#include // Core graphics library -#include // Hardware-specific library +#include // Core graphics library +#include // Hardware-specific library #include #define ILI9341_GREY 0x5AEB -Adafruit_ILI9341_AS tft = Adafruit_ILI9341_AS(cs, dc, rst); // Invoke custom library +Adafruit_ILI9341 tft = Adafruit_ILI9341(cs, dc, rst); // Invoke custom library float sx = 0, sy = 1, mx = 1, my = 0, hx = -1, hy = 0; // Saved H, M, S x & y multipliers float sdeg=0, mdeg=0, hdeg=0; diff --git a/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Rainbow_ILI9341/TFT_Rainbow_ILI9341.ino b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Rainbow_ILI9341/TFT_Rainbow_ILI9341.ino new file mode 100644 index 0000000..2fd0c4d --- /dev/null +++ b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Rainbow_ILI9341/TFT_Rainbow_ILI9341.ino @@ -0,0 +1,124 @@ +/* + An example showing rainbow colours on a 2.2" TFT LCD screen + and to show a basic example of font use. + + The existing Adafruit font is still in the library + Only new font sizes 2,4,6 and 7 are implemented in the Adafruit_GFX library. + + This examples uses the hardware SPI only. Non-hardware SPI + is just too slow (~8 times slower!) + + Alan Senior 18/1/2015 + + */ + +// These are the connections for the UNO +//#define sclk 13 // Don't change +//#define mosi 11 // Don't change +#define cs 8 +#define dc 10 +#define rst 9 // you can also connect this to the Arduino reset +#include // Core graphics library +#include // Hardware-specific library +#include + +Adafruit_ILI9341 tft = Adafruit_ILI9341(cs, dc, rst); // Invoke custom library + +unsigned long targetTime = 0; +byte red = 31; +byte green = 0; +byte blue = 0; +byte state = 0; +unsigned int colour = red << 11; + +void setup(void) { + tft.begin(); + tft.setRotation(2); + tft.fillScreen(ILI9341_BLACK); + + targetTime = millis() + 1000; +} + +void loop() { + + if (targetTime < millis()) { + targetTime = millis()+10000; + for (int i = 0; i<240; i++) { + tft.drawFastVLine(i, 0, tft.height(), colour); + switch (state) { + case 0: + green +=2; + if (green == 64) { + green=63; + state = 1; + } + break; + case 1: + red--; + if (red == 255) { + red = 0; + state = 2; + } + break; + case 2: + blue ++; + if (blue == 32) { + blue=31; + state = 3; + } + break; + case 3: + green -=2; + if (green ==255) { + green=0; + state = 4; + } + break; + case 4: + red ++; + if (red == 32) { + red = 31; + state = 5; + } + break; + case 5: + blue --; + if (blue == 255) { + blue = 0; + state = 0; + } + break; + } + colour = red<<11 | green<<5 | blue; + } + + // The standard ADAFruit font still works as berfore + tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK); // Note these fonts do not plot the background colour + tft.setCursor (68, 5); + tft.print("Original ADAfruit font!"); + + // The new larger fonts do not use the .setCursor call, coords are embedded + tft.setTextColor(ILI9341_BLACK); // Do not plot the background colour + // Overlay the black text on top of the rainbow plot (the advantage of not drawing the backgorund colour!) + tft.drawCentreString("Font size 2",120,14,2); // Draw text centre at position 120, 14 using font 2 + tft.drawCentreString("Font size 4",120,30,4); // Draw text centre at position 120, 30 using font 4 + tft.drawCentreString("12.34",120,54,6); // Draw text centre at position 120, 54 using font 6 + tft.drawCentreString("12.34 is in font size 6",120,92,2); // Draw text centre at position 120, 92 using font 2 + // Note the x position is the top of the font! + + // draw a floating point number + float pi = 3.14159; // Value to print + int precision = 3; // Number of digits after decimal point + int xpos = 90; // x position + int ypos = 110; // y position + int font = 2; // font number only 2,4,6,7 valid. Font 6 only contains characters [space] 0 1 2 3 4 5 6 7 8 9 0 : . a p m + xpos+=tft.drawFloat(pi,precision,xpos,ypos,font); // Draw rounded number and return new xpos delta for next print position + tft.drawString(" is pi",xpos,ypos,font); // Continue printing from new x position + } +} + + + + + + diff --git a/STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino similarity index 94% rename from STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino rename to STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino index 14d54df..956a69a 100644 --- a/STM32F1/libraries/Adafruit_ILI9341_AS/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino +++ b/STM32F1/libraries/Adafruit_ILI9341/examples/TFT_Show_Font_ILI9341/TFT_Show_Font_ILI9341.ino @@ -1,7 +1,7 @@ /* Sow all the fonts. - Only font sizes 2, 4, 6 and 7 are implemented in the Adafruit_GFX_AS library. + Only font sizes 2, 4, 6 and 7 are implemented in the Adafruit_GFX library. This examples uses the hardware SPI only. Non-hardware SPI is just too slow (~8 times slower!) @@ -26,17 +26,17 @@ */ -#define sclk 6 // Don't change -#define mosi 4 // Don't change +//#define sclk 6 // Don't change +//#define mosi 4 // Don't change #define cs 8 #define dc 10 #define rst 9 // you can also connect this to the Arduino reset -#include // Core graphics library -#include // Hardware-specific library +#include // Core graphics library +#include // Hardware-specific library #include -Adafruit_ILI9341_AS tft = Adafruit_ILI9341_AS(cs, dc, rst); // Invoke custom library +Adafruit_ILI9341 tft = Adafruit_ILI9341(cs, dc, rst); // Invoke custom library unsigned long targetTime = 0; byte red = 31; diff --git a/STM32F1/libraries/Adafruit_ILI9341_AS/README.txt b/STM32F1/libraries/Adafruit_ILI9341_AS/README.txt deleted file mode 100644 index 3443bec..0000000 --- a/STM32F1/libraries/Adafruit_ILI9341_AS/README.txt +++ /dev/null @@ -1,23 +0,0 @@ -It has minor modifications to support STM32. It has been tested with the Maple Mini. - -This is a library for the Adafruit ILI9341 display products - -This library works with the Adafruit 2.8" Touch Shield V2 (SPI) - ----> http://www.adafruit.com/products/1651 - -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 - -To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_ILI9341. Check that the Adafruit_ILI9341 folder contains Adafruit_ILI9341.cpp and Adafruit_ILI9341. - -Place the Adafruit_ILI9341 library folder your arduinosketchfolder/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE - -Also requires the Adafruit_GFX library for Arduino. diff --git a/STM32F1/libraries/deprecatedAdafruit_ILI9341.zip b/STM32F1/libraries/deprecatedAdafruit_ILI9341.zip new file mode 100644 index 0000000000000000000000000000000000000000..5177fd430741be42227b41c9c8a7430625b118cb GIT binary patch literal 23509 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 O?8uPBq#rTjfd2#906+); literal 0 HcmV?d00001