Uses the same fonts as the SPI_TFT_ILI9341 Library (I have many, and a html/php font editor for that)

Revision:
0:cc1fb45bc3ad
Child:
1:8e447a4c8995
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SPI_TFT_ILI9225.cpp	Wed Nov 23 01:05:59 2016 +0000
@@ -0,0 +1,833 @@
+/*
+****************                               ******************
+
+Ported to mbed platform 
+by Arman Safikhani  31 - 08-2015
+
+Jack: Many thanks Arman!
+
+Changed:
+by Jack Berkhout 23-11-2016
+- uses the same fonts as the SPI_TFT_ILI9341 Library (I have many, and a html/php editor for that)
+- some code removed, some added, some changed
+- the led backlight is using a PWM output, so it can be adjusted (0.0f = off - 1.0f = on)
+- added formatted printf
+- added claim as standard output on stream
+
+* ***************                               ******************
+*/
+
+#include "SPI_TFT_ILI9225.h"
+#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
+
+int font_color, x_font, y_font;
+char highlight, fa_num;
+int effect = 0, italic = 0;
+unsigned int highlight_color;
+/* Global Variables */
+int x_text = 0, y_text = 0;
+int x_base = 0;
+
+// Constructor when using software SPI.  All output pins are configurable.
+TFT_22_ILI9225::TFT_22_ILI9225(PinName sdi, PinName clk, PinName cs, PinName rs, PinName rst, PinName led, const char *name) :
+    spi(sdi, NC, clk), _cs(cs), _rs(rs), _rst(rst), _led(led), Stream(name)
+{
+    spi.frequency(24000000); 
+    spi.format(8, 0);
+
+    // PWM output to control backlight
+    _led.period_ms(10);
+
+    // --- claim ---
+    _row = 0;
+    _column = 0;
+    if (name == NULL) {
+        _path = NULL;
+    } else {
+        _path = new char[strlen(name) + 2];
+        sprintf(_path, "/%s", name);
+    }
+    // --- /claim ---
+    
+    init();
+}
+
+bool TFT_22_ILI9225::claim (FILE *stream) {
+    if ( _path == NULL) {
+        fprintf(stderr, "claim requires a name to be given in the instantioator of the TextDisplay instance!\r\n");
+        return false;
+    }
+    if (freopen(_path, "w", stream) == NULL) {
+        // Failed, should not happen
+        return false;
+    }
+    // make sure we use line buffering
+    setvbuf(stdout, NULL, _IOLBF, ILI9225_CHARS_PER_LINE);
+    return true;
+} 
+
+void TFT_22_ILI9225::_orientCoordinates(uint16_t &x1, uint16_t &y1) {
+
+    switch (_orientation) {
+        case 0:  // ok
+            break;
+        case 1: // ok
+            y1 = _maxY - y1 - 1;
+            _swap(x1, y1);
+            break;
+        case 2: // ok
+            x1 = _maxX - x1 - 1;
+            y1 = _maxY - y1 - 1;
+            break;
+        case 3: // ok
+            x1 = _maxX - x1 - 1;
+            _swap(x1, y1);
+            break;
+    }
+}
+
+void TFT_22_ILI9225::_setWindowMax(void) {
+    _setWindow(0, 0, maxX(), maxY());
+}
+
+void TFT_22_ILI9225::_setWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
+    _orientCoordinates(x0, y0);
+    _orientCoordinates(x1, y1);
+
+    if (x1 < x0) _swap(x0, x1);
+    if (y1 < y0) _swap(y0, y1);
+
+    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1, x1);
+    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2, x0);
+
+    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1, y1);
+    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2, y0);
+
+    _writeRegister(ILI9225_RAM_ADDR_SET1, x0);
+    _writeRegister(ILI9225_RAM_ADDR_SET2, y0);
+
+    _writeCommand(0x00, 0x22);
+}
+
+void TFT_22_ILI9225::init()
+{
+    // Turn off backlight
+    setBacklight(0.0f);
+
+    // Initialization Code
+    _rst = 0;// Pull the reset pin low to reset ILI9225
+    wait_ms(10);
+    _rst = 1;// Pull the reset pin high to release the ILI9225C from the reset status
+    wait_ms(50);
+
+    /* Start Initial Sequence */
+    /* Set SS bit and direction output from S528 to S1 */
+    _writeRegister(ILI9225_POWER_CTRL1, 0x0000); // Set SAP,DSTB,STB
+    _writeRegister(ILI9225_POWER_CTRL2, 0x0000); // Set APON,PON,AON,VCI1EN,VC
+    _writeRegister(ILI9225_POWER_CTRL3, 0x0000); // Set BT,DC1,DC2,DC3
+    _writeRegister(ILI9225_POWER_CTRL4, 0x0000); // Set GVDD
+    _writeRegister(ILI9225_POWER_CTRL5, 0x0000); // Set VCOMH/VCOML voltage
+    wait_ms(40);
+
+    // Power-on sequence
+    _writeRegister(ILI9225_POWER_CTRL2, 0x0018); // Set APON,PON,AON,VCI1EN,VC
+    _writeRegister(ILI9225_POWER_CTRL3, 0x6121); // Set BT,DC1,DC2,DC3
+    _writeRegister(ILI9225_POWER_CTRL4, 0x006F); // Set GVDD   /*007F 0088 */
+    _writeRegister(ILI9225_POWER_CTRL5, 0x495F); // Set VCOMH/VCOML voltage
+    _writeRegister(ILI9225_POWER_CTRL1, 0x0800); // Set SAP,DSTB,STB
+    wait_ms(10);
+    _writeRegister(ILI9225_POWER_CTRL2, 0x103B); // Set APON,PON,AON,VCI1EN,VC
+    wait_ms(50);
+
+    _writeRegister(ILI9225_DRIVER_OUTPUT_CTRL, 0x011C); // set the display line number and display direction
+    _writeRegister(ILI9225_LCD_AC_DRIVING_CTRL, 0x0100); // set 1 line inversion
+    _writeRegister(ILI9225_ENTRY_MODE, 0x1030); // set GRAM write direction and BGR=1.
+    _writeRegister(ILI9225_DISP_CTRL1, 0x0000); // Display off
+    _writeRegister(ILI9225_BLANK_PERIOD_CTRL1, 0x0808); // set the back porch and front porch
+    _writeRegister(ILI9225_FRAME_CYCLE_CTRL, 0x1100); // set the clocks number per line
+    _writeRegister(ILI9225_INTERFACE_CTRL, 0x0000); // CPU interface
+    _writeRegister(ILI9225_OSC_CTRL, 0x0D01); // Set Osc  /*0e01*/
+    _writeRegister(ILI9225_VCI_RECYCLING, 0x0020); // Set VCI recycling
+    _writeRegister(ILI9225_RAM_ADDR_SET1, 0x0000); // RAM Address
+    _writeRegister(ILI9225_RAM_ADDR_SET2, 0x0000); // RAM Address
+
+                                                   /* Set GRAM area */
+    _writeRegister(ILI9225_GATE_SCAN_CTRL, 0x0000);
+    _writeRegister(ILI9225_VERTICAL_SCROLL_CTRL1, 0x00DB);
+    _writeRegister(ILI9225_VERTICAL_SCROLL_CTRL2, 0x0000);
+    _writeRegister(ILI9225_VERTICAL_SCROLL_CTRL3, 0x0000);
+    _writeRegister(ILI9225_PARTIAL_DRIVING_POS1, 0x00DB);
+    _writeRegister(ILI9225_PARTIAL_DRIVING_POS2, 0x0000);
+    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR1, 0x00AF);
+    _writeRegister(ILI9225_HORIZONTAL_WINDOW_ADDR2, 0x0000);
+    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR1, 0x00DB);
+    _writeRegister(ILI9225_VERTICAL_WINDOW_ADDR2, 0x0000);
+
+    /* Set GAMMA curve */
+    _writeRegister(ILI9225_GAMMA_CTRL1, 0x0000);
+    _writeRegister(ILI9225_GAMMA_CTRL2, 0x0808);
+    _writeRegister(ILI9225_GAMMA_CTRL3, 0x080A);
+    _writeRegister(ILI9225_GAMMA_CTRL4, 0x000A);
+    _writeRegister(ILI9225_GAMMA_CTRL5, 0x0A08);
+    _writeRegister(ILI9225_GAMMA_CTRL6, 0x0808);
+    _writeRegister(ILI9225_GAMMA_CTRL7, 0x0000);
+    _writeRegister(ILI9225_GAMMA_CTRL8, 0x0A00);
+    _writeRegister(ILI9225_GAMMA_CTRL9, 0x0710);
+    _writeRegister(ILI9225_GAMMA_CTRL10, 0x0710);
+
+    _writeRegister(ILI9225_DISP_CTRL1, 0x0012);
+    wait_ms(50);
+    _writeRegister(ILI9225_DISP_CTRL1, 0x1017);
+
+    cls();
+    linespacing(0);
+    setBacklight(1.0f);
+    setOrientation(ILI9225_LANDSCAPE_R);
+    foreground(COLOR_WHITE);
+    background(COLOR_BLACK);
+}
+
+void TFT_22_ILI9225::cls() {
+    setBacklightOff();
+    _setWindowMax();
+    _rs = 1;
+    _cs = 0;
+    for (uint16_t i = width() * height(); i > 0; i--) {
+        spi.write(0x00);
+        spi.write(0x00);
+    }
+    _cs = 1;
+    setBacklightOn();
+    gotoxy(0, 0);
+}
+
+void TFT_22_ILI9225::fill(uint16_t color)
+{
+    fillRectangle(0, 0, maxX(), maxY(), color);
+}
+
+void TFT_22_ILI9225::invert(bool flag) {
+    _writeCommand(0x00, flag ? ILI9225C_INVON : ILI9225C_INVOFF);
+}
+
+void TFT_22_ILI9225::setBacklight(double brightness) {
+    // PWM output to control backlight
+    _brightness = brightness;
+    _led.write(pow(brightness, 2)); // power(x, 2): For the eye better brightness response
+}
+
+void TFT_22_ILI9225::setBacklightOff(void) {
+    _led.write(0.0f);
+}
+
+void TFT_22_ILI9225::setBacklightOn(void) {
+    setBacklight(_brightness);
+}
+
+void TFT_22_ILI9225::setDisplay(bool flag) {
+    if (flag) {
+        _writeRegister(0x00ff, 0x0000);
+        _writeRegister(ILI9225_POWER_CTRL1, 0x0000);
+        wait_ms(50);
+        _writeRegister(ILI9225_DISP_CTRL1, 0x1017);
+        wait_ms(200);
+    }
+    else {
+        _writeRegister(0x00ff, 0x0000);
+        _writeRegister(ILI9225_DISP_CTRL1, 0x0000);
+        wait_ms(50);
+        _writeRegister(ILI9225_POWER_CTRL1, 0x0003);
+        wait_ms(200);
+    }
+}
+
+void TFT_22_ILI9225::setOrientation(uint8_t orientation) {
+
+    _orientation = orientation % 4;
+
+    switch (_orientation) {
+    case 0:
+        _maxX = ILI9225_LCD_WIDTH;
+        _maxY = ILI9225_LCD_HEIGHT;
+        break;
+    case 1:
+        _maxX = ILI9225_LCD_HEIGHT;
+        _maxY = ILI9225_LCD_WIDTH;
+        break;
+    case 2:
+        _maxX = ILI9225_LCD_WIDTH;
+        _maxY = ILI9225_LCD_HEIGHT;
+        break;
+    case 3:
+        _maxX = ILI9225_LCD_HEIGHT;
+        _maxY = ILI9225_LCD_WIDTH;
+        break;
+    }
+}
+
+uint8_t TFT_22_ILI9225::getOrientation() {
+    return _orientation;
+}
+
+void TFT_22_ILI9225::drawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
+    drawLine(x1, y1, x1, y2, color);
+    drawLine(x1, y1, x2, y1, color);
+    drawLine(x1, y2, x2, y2, color);
+    drawLine(x2, y1, x2, y2, color);
+}
+
+void TFT_22_ILI9225::fillRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
+
+    _setWindow(x1, y1, x2, y2);
+    _startData();
+    for (uint16_t t = (y2 - y1 + 1) * (x2 - x1 + 1); t > 0; t--) {
+        _writeData(color);
+    }
+    _endData();
+}
+
+void TFT_22_ILI9225::drawCircle(uint16_t x0, uint16_t y0, uint16_t r, uint16_t color) {
+
+    int16_t f = 1 - r;
+    int16_t ddF_x = 1;
+    int16_t ddF_y = -2 * r;
+    int16_t x = 0;
+    int16_t y = r;
+
+    drawPixel(x0, y0 + r, color);
+    drawPixel(x0, y0 - r, color);
+    drawPixel(x0 + r, y0, color);
+    drawPixel(x0 - r, y0, color);
+
+    while (x < y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f += ddF_x;
+
+        drawPixel(x0 + x, y0 + y, color);
+        drawPixel(x0 - x, y0 + y, color);
+        drawPixel(x0 + x, y0 - y, color);
+        drawPixel(x0 - x, y0 - y, color);
+        drawPixel(x0 + y, y0 + x, color);
+        drawPixel(x0 - y, y0 + x, color);
+        drawPixel(x0 + y, y0 - x, color);
+        drawPixel(x0 - y, y0 - x, color);
+    }
+}
+
+void TFT_22_ILI9225::fillCircle(uint8_t x0, uint8_t y0, uint8_t radius, uint16_t color) {
+
+    int16_t f = 1 - radius;
+    int16_t ddF_x = 1;
+    int16_t ddF_y = -2 * radius;
+    int16_t x = 0;
+    int16_t y = radius;
+
+    while (x < y) {
+        if (f >= 0) {
+            y--;
+            ddF_y += 2;
+            f += ddF_y;
+        }
+        x++;
+        ddF_x += 2;
+        f += ddF_x;
+
+        drawLine(x0 + x, y0 + y, x0 - x, y0 + y, color); // bottom
+        drawLine(x0 + x, y0 - y, x0 - x, y0 - y, color); // top
+        drawLine(x0 + y, y0 - x, x0 + y, y0 + x, color); // right
+        drawLine(x0 - y, y0 - x, x0 - y, y0 + x, color); // left
+    }
+    fillRectangle(x0 - x, y0 - y, x0 + x, y0 + y, color);
+}
+
+void TFT_22_ILI9225::drawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
+
+    // Classic Bresenham algorithm
+    int16_t steep = abs(y2 - y1) > abs(x2 - x1);
+    int16_t dx, dy;
+
+    if (steep) {
+        _swap(x1, y1);
+        _swap(x2, y2);
+    }
+
+    if (x1 > x2) {
+        _swap(x1, x2);
+        _swap(y1, y2);
+    }
+
+    dx = x2 - x1;
+    dy = abs(y2 - y1);
+
+    int16_t err = dx / 2;
+    int16_t ystep;
+
+    if (y1 < y2) ystep = 1;
+    else ystep = -1;
+
+
+    for (; x1 <= x2; x1++) {
+        if (steep) drawPixel(y1, x1, color);
+        else       drawPixel(x1, y1, color);
+
+        err -= dy;
+        if (err < 0) {
+            y1 += ystep;
+            err += dx;
+        }
+    }
+}
+
+void TFT_22_ILI9225::drawPixel(uint16_t x1, uint16_t y1, uint16_t color) {
+
+    if ((x1 >= _maxX) || (y1 >= _maxY)) return;
+
+    _setWindow(x1, y1, x1 + 1, y1 + 1);
+    _orientCoordinates(x1, y1);
+    _startData();
+    _writeData(color);
+    _endData();
+}
+
+uint16_t TFT_22_ILI9225::maxX(void) {
+    return _maxX - 1;
+}
+
+uint16_t TFT_22_ILI9225::maxY(void) {
+    return _maxY - 1;
+}
+
+uint16_t TFT_22_ILI9225::width(void) {
+    return _maxX;
+}
+
+uint16_t TFT_22_ILI9225::height(void) {
+    return _maxY;
+}
+
+uint16_t TFT_22_ILI9225::setColor(uint8_t red8, uint8_t green8, uint8_t blue8) {
+    // rgb16 = red5 green6 blue5
+    return (red8 >> 3) << 11 | (green8 >> 2) << 5 | (blue8 >> 3);
+}
+
+void TFT_22_ILI9225::splitColor(uint16_t rgb, uint8_t &red, uint8_t &green, uint8_t &blue) {
+    // rgb16 = red5 green6 blue5
+    
+    red = (rgb & 0xF800) >> 11 << 3;
+    green = (rgb & 0x7E0) >> 5 << 2;
+    blue = (rgb & 0x1F) << 3;
+}
+
+void TFT_22_ILI9225::_swap(uint16_t &a, uint16_t &b) {
+    uint16_t w = a;
+    a = b;
+    b = w;
+}
+
+void TFT_22_ILI9225::_writeCommand(uint8_t HI, uint8_t LO) {
+    _rs = 0;
+    _cs = 0;
+    spi.write(HI);
+    spi.write(LO);
+    _cs = 1;
+}
+
+void TFT_22_ILI9225::_writeData(uint16_t data) {
+    spi.write(data >> 8);
+    spi.write(data & 0xff);
+//    spi.write(data);
+}
+
+void TFT_22_ILI9225::_startData(void) {
+    _rs = 1;
+    _cs = 0;
+//    spi.format(16, 0);    // New mbed library can't use 16 bit spi anymore on this platform
+}
+
+void TFT_22_ILI9225::_endData(void) {
+    _cs = 1;
+//    spi.format(8, 0);
+}
+
+void TFT_22_ILI9225::_writeRegister(uint16_t reg, uint16_t data) {
+    _writeCommand(reg >> 8, reg & 0xff);
+    _startData();
+    _writeData(data);
+    _endData();
+}
+
+void TFT_22_ILI9225::drawTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color) {
+    drawLine(x1, y1, x2, y2, color);
+    drawLine(x2, y2, x3, y3, color);
+    drawLine(x3, y3, x1, y1, color);
+}
+
+void TFT_22_ILI9225::fillTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color) {
+
+    uint16_t a, b, y, last;
+
+    // Sort coordinates by Y order (y3 >= y2 >= y1)
+    if (y1 > y2) {
+        _swap(y1, y2); _swap(x1, x2);
+    }
+    if (y2 > y3) {
+        _swap(y3, y2); _swap(x3, x2);
+    }
+    if (y1 > y2) {
+        _swap(y1, y2); _swap(x1, x2);
+    }
+
+    if (y1 == y3) { // Handle awkward all-on-same-line case as its own thing
+        a = b = x1;
+        if (x2 < a)      a = x2;
+        else if (x2 > b) b = x2;
+        if (x3 < a)      a = x3;
+        else if (x3 > b) b = x3;
+        drawLine(a, y1, b, y1, color);
+        return;
+    }
+
+    uint16_t    dx11 = x2 - x1,
+        dy11 = y2 - y1,
+        dx12 = x3 - x1,
+        dy12 = y3 - y1,
+        dx22 = x3 - x2,
+        dy22 = y3 - y2,
+        sa = 0,
+        sb = 0;
+
+    // For upper part of triangle, find scanline crossings for segments
+    // 0-1 and 0-2.  If y2=y3 (flat-bottomed triangle), the scanline y2
+    // is included here (and second loop will be skipped, avoiding a /0
+    // error there), otherwise scanline y2 is skipped here and handled
+    // in the second loop...which also avoids a /0 error here if y1=y2
+    // (flat-topped triangle).
+    if (y2 == y3) last = y2;   // Include y2 scanline
+    else          last = y2 - 1; // Skip it
+
+    for (y = y1; y <= last; y++) {
+        a = x1 + sa / dy11;
+        b = x1 + sb / dy12;
+        sa += dx11;
+        sb += dx12;
+        /* longhand:
+        a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
+        b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+        */
+        if (a > b) _swap(a, b);
+        drawLine(a, y, b, y, color);
+    }
+
+    // For lower part of triangle, find scanline crossings for segments
+    // 0-2 and 1-2.  This loop is skipped if y2=y3.
+    sa = dx22 * (y - y2);
+    sb = dx12 * (y - y1);
+    for (; y <= y3; y++) {
+        a = x2 + sa / dy22;
+        b = x1 + sb / dy12;
+        sa += dx22;
+        sb += dx12;
+        /* longhand:
+        a = x2 + (x3 - x2) * (y - y2) / (y3 - y2);
+        b = x1 + (x3 - x1) * (y - y1) / (y3 - y1);
+        */
+        if (a > b) _swap(a, b);
+        drawLine(a, y, b, y, color);
+    }
+}
+
+void TFT_22_ILI9225::setFont(unsigned char* f) {
+    font = f;
+}
+
+int TFT_22_ILI9225::putc(int value)
+{
+    if (value == '\n') {    // new line
+        char_x = 0;
+        char_y = char_y + (font[FONT_VERT] + char_line_spacing);
+        if (char_y >= height() - (font[FONT_VERT] + char_line_spacing)) {
+            char_y = 0;
+        }
+        return value;
+    }
+    if ((value < 32) || (value > 127)) {
+        return value;
+    }
+    character(char_x, char_y, value);
+    return value;
+}
+
+void TFT_22_ILI9225::character(int x, int y, int c)
+{
+    unsigned int hor, vert, offset, bpl, b;
+    unsigned char* zeichen;
+    unsigned char z,w;
+
+    if ((c < 31) || (c > 127)) return;   // test char range
+
+    // read font parameter from start of array
+    offset = font[FONT_LENGTH];         // bytes / char
+    hor    = font[FONT_HORZ];           // get hor size of font
+    vert   = font[FONT_VERT];           // get vert size of font
+    bpl    = font[FONT_BYTES_VERT];     // bytes per line
+
+    if (char_x + hor > width()) {
+        char_x = 0;
+        char_y = char_y + vert + char_line_spacing;
+        if (char_y >= height() - (vert + char_line_spacing)) {
+            char_y = 0;
+        }
+    }
+    _setWindow(char_x, char_y, (char_x+hor)-1, (char_y+vert)-1);
+
+    zeichen = &font[((c -32) * offset) + 4]; // start of char bitmap
+    w = zeichen[0];                          // width of actual char
+    _startData();
+
+    switch (_orientation) {
+        case 0:
+            // Portrait
+            for (int j=0; j < vert; j++) {  //  vert line
+                for (int i=0; i<hor; i++) {   //  horz line
+                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
+                    b = 1 << (j & 0x07);
+                    if (( z & b ) == 0x00) {
+                        spi.write(_background >> 8);
+                        spi.write(_background & 0xff);
+                    } else {
+                        spi.write(_foreground >> 8);
+                        spi.write(_foreground & 0xff);
+                    }
+                }
+            }
+            break;
+        case 1:
+            // Landscape
+            for (int i=0; i<hor; i++) {   //  horz line
+                for (int j=vert-1; j>=0; j--) {  //  vert line
+                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
+                    b = 1 << (j & 0x07);
+                    if (( z & b ) == 0x00) {
+                        spi.write(_background >> 8);
+                        spi.write(_background & 0xff);
+                    } else {
+                        spi.write(_foreground >> 8);
+                        spi.write(_foreground & 0xff);
+                    }
+                }
+            }
+            break;
+        case 2:
+            // Portrait
+            for (int j=vert-1; j>=0; j--) {  //  vert line
+                for (int i=hor-1; i>=0; i--) {   //  horz line
+                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
+                    b = 1 << (j & 0x07);
+                    if (( z & b ) == 0x00) {
+                        spi.write(_background >> 8);
+                        spi.write(_background & 0xff);
+                    } else {
+                        spi.write(_foreground >> 8);
+                        spi.write(_foreground & 0xff);
+                    }
+                }
+            }
+            break;
+        case 3:
+            // Landscape
+            for (int i=hor-1; i>= 0; i--) {   //  horz line
+                for (int j=0; j<vert; j++) {  //  vert line
+                    z =  zeichen[bpl * i + ((j & 0xF8) >> 3)+1];
+                    b = 1 << (j & 0x07);
+                    if (( z & b ) == 0x00) {
+                        spi.write(_background >> 8);
+                        spi.write(_background & 0xff);
+                    } else {
+                        spi.write(_foreground >> 8);
+                        spi.write(_foreground & 0xff);
+                    }
+                }
+            }
+            break;
+    }
+    
+    _endData();
+    _setWindowMax();
+    if ((w + 2) < hor) {                   // x offset to next char
+        char_x += w + 2;
+    } else char_x += hor;
+}
+        
+void TFT_22_ILI9225::foreground(uint16_t colour) {
+    _foreground = colour;
+}
+
+void TFT_22_ILI9225::background(uint16_t colour) {
+    _background = colour;
+}
+
+void TFT_22_ILI9225::locate(int x, int y)
+{
+    char_x = x;
+    char_y = y;
+}
+
+void TFT_22_ILI9225::gotoxy(int x, int y)
+{
+    char_x = x * font[FONT_HORZ];
+    char_y = y * (font[FONT_VERT] + char_line_spacing);
+}
+
+void TFT_22_ILI9225::home(void)
+{
+    gotoxy(0, 0);
+}
+
+void TFT_22_ILI9225::linespacing(int line_spacing)
+{
+    char_line_spacing = line_spacing;
+}
+
+int TFT_22_ILI9225::columns()
+{
+    return width() / font[FONT_HORZ];
+}
+
+int TFT_22_ILI9225::rows()
+{
+    return height() / font[FONT_VERT];
+}
+
+//----------------------------------------------------------------------------------------------------
+//************************************* ECA 2.8 inch LCD Module **************************************
+//----------------------------------------------------------------------------------------------------
+// Description  : Draws a beveled figure on the screen. 
+// Input        : x0, y0 - coordinate position of the upper left center
+//                  : x1, y1 - coordinate position of the lower right center
+//              : rad    - defines the redius of the circle,
+//              : fill   - fill yes or no
+//----------------------------------------------------------------------------------------------------
+void TFT_22_ILI9225::roundRectangle(int x0, int y0, int x1, int y1, int rad, bool fill, int color)
+{
+    signed int a, b, P;
+
+    a = 0;                      // increment by 1
+    b = rad;                // decrement by 1 using P
+    P = 1 - rad;
+
+
+    if (fill)
+    {
+        fillRectangle(x0, y0 + rad, x1, y1 - rad, color);
+
+        do
+        {
+            fillRectangle(x0 - a + rad, y0 - b + rad, a + x1 - rad, y0 - b + rad, color);   // 8 --> 1
+            fillRectangle(x0 - b + rad, y0 - a + rad, b + x1 - rad, y0 - a + rad, color);   // 7 --> 2
+            fillRectangle(x0 - b + rad, a + y1 - rad, b + x1 - rad, a + y1 - rad, color);   // 6 --> 3
+            fillRectangle(x0 - a + rad, b + y1 - rad, a + x1 - rad, b + y1 - rad, color);   // 5 --> 4
+
+            if (P < 0)
+                P += 3 + 2 * a++;
+            else
+                P += 5 + 2 * (a++ - b--);
+
+        } while (a <= b);
+    } //fill
+    else
+    {
+        fillRectangle(x0 + rad, y0, x1 - rad, y0, color);   // top
+        fillRectangle(x0 + rad, y1, x1 - rad, y1, color);   // bottom
+        fillRectangle(x0, y0 + rad, x0, y1 - rad, color);   // left
+        fillRectangle(x1, y0 + rad, x1, y1 - rad, color);   // right
+
+        do
+        {
+            drawPixel(a + x1 - rad, y0 - b + rad, color);   // `````` Segment 1
+            drawPixel(b + x1 - rad, y0 - a + rad, color);   // `````` Segment 2
+
+            drawPixel(b + x1 - rad, a + y1 - rad, color);   // `````` Segment 3
+            drawPixel(a + x1 - rad, b + y1 - rad, color);   // `````` Segment 4
+
+            drawPixel(x0 - a + rad, b + y1 - rad, color);   // `````` Segment 5
+            drawPixel(x0 - b + rad, a + y1 - rad, color);   // `````` Segment 6
+
+            drawPixel(x0 - b + rad, y0 - a + rad, color);   // `````` Segment 7
+            drawPixel(x0 - a + rad, y0 - b + rad, color);   // `````` Segment 8
+
+            if (P < 0)
+                P += 3 + 2 * a++;
+            else
+                P += 5 + 2 * (a++ - b--);
+        } while (a <= b);
+    } //no fill
+}   //RoundRectangle
+
+//----------------------------------------------------------------------------------------------------
+//************************************* ECA 2.8 inch LCD Module **************************************
+//----------------------------------------------------------------------------------------------------
+// Make an ascii string from an unicode string 
+//----------------------------------------------------------------------------------------------------
+
+void TFT_22_ILI9225::unicode2ascii(char *uni_str, char *ascii_str)
+{
+    int counter = 0;
+    int Uch = 0;
+    char chl, chh;
+
+
+    while (*uni_str)
+    {
+        chl = *uni_str++;
+        chh = *uni_str++;
+
+        Uch = 0;
+        Uch = ((Uch | chh) << 8) | chl;
+
+        if (Uch > 1574 && Uch < 1591)
+            *(ascii_str + counter) = (char)(Uch - 1376);
+        else if (Uch > 1590 && Uch < 1595)
+            *(ascii_str + counter) = (char)(Uch - 1375);
+        else if (Uch > 1600 && Uch < 1603)
+            *(ascii_str + counter) = (char)(Uch - 1380);
+        else if (Uch == 1705)
+            *(ascii_str + counter) = (char)(Uch - 1482);
+        else if (Uch == 1604)
+            *(ascii_str + counter) = (char)(Uch - 1379);
+        else if (Uch > 1604 && Uch < 1609)
+            *(ascii_str + counter) = (char)(Uch - 1378);
+        else if (Uch == 1740)
+            *(ascii_str + counter) = (char)(Uch - 1503);
+        else if (Uch == 1574)
+            *(ascii_str + counter) = (char)(Uch - 1381);
+        else if (Uch == 1662)
+            *(ascii_str + counter) = (char)(Uch - 1533);
+        else if (Uch == 1670)
+            *(ascii_str + counter) = (char)(Uch - 1529);
+        else if (Uch == 1688)
+            *(ascii_str + counter) = (char)(Uch - 1546);
+        else if (Uch == 1711)
+            *(ascii_str + counter) = (char)(Uch - 1567);
+        else if (Uch == 1570)
+            *(ascii_str + counter) = (char)(Uch - 1376);
+        else if (Uch > 1631 && Uch < 1642)
+            *(ascii_str + counter) = (char)(Uch - 1584);
+        else if (Uch == 65536)
+            *(ascii_str + counter) = NULL;
+        else
+            *(ascii_str + counter) = (char)Uch;
+
+
+        counter++;
+
+    }
+    *(ascii_str + counter) = NULL;
+
+}
+