mirror of
https://github.com/smartykit/apple1.git
synced 2024-09-07 23:54:29 +00:00
1563 lines
51 KiB
C++
1563 lines
51 KiB
C++
/* SmartyKit 1 - 2.8" TFT 320x240 screen video driver (+TV)
|
||
* http://www.smartykit.io/
|
||
* Copyright (C) 2019, Sergey Panarin <contact@smartykit.io>
|
||
*
|
||
This program is free software: you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation, either version 3 of the License, or
|
||
(at your option) any later version.
|
||
This program 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 General Public License for more details.
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#define _SMARTYKIT_DISPLAY_DRIVER_IL9341H_
|
||
#define _SMARTY_DEBUG_
|
||
|
||
#include <SPI.h>
|
||
|
||
|
||
#include <Terminal.h>
|
||
#undef _TERMINAL_ //turn off Terminal
|
||
//#define _TERMINAL_ //turn on Terminal
|
||
|
||
#ifdef _TERMINAL_
|
||
// Create a terminal in TWI mode
|
||
Terminal term; //uses A4 (SDA) and A5 (SCL) that conflict with other usage of A4-A5
|
||
//so we need to put CS on low, RST = A0, DC = A1, MOSI = A2, SCK = A3, MISO = not connected (NC)
|
||
#endif
|
||
|
||
|
||
// Video Driver pins connections:
|
||
// D0 & D1 – reserved for Serial connection
|
||
// D2 -> NC
|
||
// D3 –> 4-16 ports decoder Video (9) out pin (signal is active when CPU writes to Video port)
|
||
// D4 -> NC
|
||
// D5 -> Video BIT7 pin output
|
||
// D6-D13 -> Video data bus input (8 pins) to connect to Video port (char code is transfered here)
|
||
// A0-A3 -> 2.8" TFT 320x240 screen connection
|
||
// A4-A5 -> TV terminal via I2C (TWI)
|
||
|
||
// Standard ASCII 5x7 font
|
||
|
||
static const unsigned char font[] PROGMEM = {
|
||
0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x3E, 0x6B,
|
||
0x4F, 0x6B, 0x3E, 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x18, 0x3C, 0x7E, 0x3C,
|
||
0x18, 0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00,
|
||
0x18, 0x3C, 0x18, 0x00, 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00, 0x18, 0x24,
|
||
0x18, 0x00, 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x30, 0x48, 0x3A, 0x06, 0x0E,
|
||
0x26, 0x29, 0x79, 0x29, 0x26, 0x40, 0x7F, 0x05, 0x05, 0x07, 0x40, 0x7F,
|
||
0x05, 0x25, 0x3F, 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x7F, 0x3E, 0x1C, 0x1C,
|
||
0x08, 0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x14, 0x22, 0x7F, 0x22, 0x14, 0x5F,
|
||
0x5F, 0x00, 0x5F, 0x5F, 0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00, 0x66, 0x89,
|
||
0x95, 0x6A, 0x60, 0x60, 0x60, 0x60, 0x60, 0x94, 0xA2, 0xFF, 0xA2, 0x94,
|
||
0x08, 0x04, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x20, 0x10, 0x08, 0x08,
|
||
0x2A, 0x1C, 0x08, 0x08, 0x1C, 0x2A, 0x08, 0x08, 0x1E, 0x10, 0x10, 0x10,
|
||
0x10, 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x30, 0x38, 0x3E, 0x38, 0x30, 0x06,
|
||
0x0E, 0x3E, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5F,
|
||
0x00, 0x00, 0x00, 0x07, 0x00, 0x07, 0x00, 0x14, 0x7F, 0x14, 0x7F, 0x14,
|
||
0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x23, 0x13, 0x08, 0x64, 0x62, 0x36, 0x49,
|
||
0x56, 0x20, 0x50, 0x00, 0x08, 0x07, 0x03, 0x00, 0x00, 0x1C, 0x22, 0x41,
|
||
0x00, 0x00, 0x41, 0x22, 0x1C, 0x00, 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x08,
|
||
0x08, 0x3E, 0x08, 0x08, 0x00, 0x80, 0x70, 0x30, 0x00, 0x08, 0x08, 0x08,
|
||
0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02,
|
||
0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00, 0x42, 0x7F, 0x40, 0x00, 0x72, 0x49,
|
||
0x49, 0x49, 0x46, 0x21, 0x41, 0x49, 0x4D, 0x33, 0x18, 0x14, 0x12, 0x7F,
|
||
0x10, 0x27, 0x45, 0x45, 0x45, 0x39, 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x41,
|
||
0x21, 0x11, 0x09, 0x07, 0x36, 0x49, 0x49, 0x49, 0x36, 0x46, 0x49, 0x49,
|
||
0x29, 0x1E, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00,
|
||
0x00, 0x08, 0x14, 0x22, 0x41, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x41,
|
||
0x22, 0x14, 0x08, 0x02, 0x01, 0x59, 0x09, 0x06, 0x3E, 0x41, 0x5D, 0x59,
|
||
0x4E, 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x7F, 0x49, 0x49, 0x49, 0x36, 0x3E,
|
||
0x41, 0x41, 0x41, 0x22, 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x7F, 0x49, 0x49,
|
||
0x49, 0x41, 0x7F, 0x09, 0x09, 0x09, 0x01, 0x3E, 0x41, 0x41, 0x51, 0x73,
|
||
0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00, 0x41, 0x7F, 0x41, 0x00, 0x20, 0x40,
|
||
0x41, 0x3F, 0x01, 0x7F, 0x08, 0x14, 0x22, 0x41, 0x7F, 0x40, 0x40, 0x40,
|
||
0x40, 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x3E,
|
||
0x41, 0x41, 0x41, 0x3E, 0x7F, 0x09, 0x09, 0x09, 0x06, 0x3E, 0x41, 0x51,
|
||
0x21, 0x5E, 0x7F, 0x09, 0x19, 0x29, 0x46, 0x26, 0x49, 0x49, 0x49, 0x32,
|
||
0x03, 0x01, 0x7F, 0x01, 0x03, 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x1F, 0x20,
|
||
0x40, 0x20, 0x1F, 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x63, 0x14, 0x08, 0x14,
|
||
0x63, 0x03, 0x04, 0x78, 0x04, 0x03, 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
|
||
0x7F, 0x41, 0x41, 0x41, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x41, 0x41,
|
||
0x41, 0x7F, 0x04, 0x02, 0x01, 0x02, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40,
|
||
0x00, 0x03, 0x07, 0x08, 0x00, 0x20, 0x54, 0x54, 0x78, 0x40, 0x7F, 0x28,
|
||
0x44, 0x44, 0x38, 0x38, 0x44, 0x44, 0x44, 0x28, 0x38, 0x44, 0x44, 0x28,
|
||
0x7F, 0x38, 0x54, 0x54, 0x54, 0x18, 0x00, 0x08, 0x7E, 0x09, 0x02, 0x18,
|
||
0xA4, 0xA4, 0x9C, 0x78, 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00, 0x44, 0x7D,
|
||
0x40, 0x00, 0x20, 0x40, 0x40, 0x3D, 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,
|
||
0x00, 0x41, 0x7F, 0x40, 0x00, 0x7C, 0x04, 0x78, 0x04, 0x78, 0x7C, 0x08,
|
||
0x04, 0x04, 0x78, 0x38, 0x44, 0x44, 0x44, 0x38, 0xFC, 0x18, 0x24, 0x24,
|
||
0x18, 0x18, 0x24, 0x24, 0x18, 0xFC, 0x7C, 0x08, 0x04, 0x04, 0x08, 0x48,
|
||
0x54, 0x54, 0x54, 0x24, 0x04, 0x04, 0x3F, 0x44, 0x24, 0x3C, 0x40, 0x40,
|
||
0x20, 0x7C, 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x3C, 0x40, 0x30, 0x40, 0x3C,
|
||
0x44, 0x28, 0x10, 0x28, 0x44, 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x44, 0x64,
|
||
0x54, 0x4C, 0x44, 0x00, 0x08, 0x36, 0x41, 0x00, 0x00, 0x00, 0x77, 0x00,
|
||
0x00, 0x00, 0x41, 0x36, 0x08, 0x00, 0x02, 0x01, 0x02, 0x04, 0x02, 0x3C,
|
||
0x26, 0x23, 0x26, 0x3C, 0x1E, 0xA1, 0xA1, 0x61, 0x12, 0x3A, 0x40, 0x40,
|
||
0x20, 0x7A, 0x38, 0x54, 0x54, 0x55, 0x59, 0x21, 0x55, 0x55, 0x79, 0x41,
|
||
0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut
|
||
0x21, 0x55, 0x54, 0x78, 0x40, 0x20, 0x54, 0x55, 0x79, 0x40, 0x0C, 0x1E,
|
||
0x52, 0x72, 0x12, 0x39, 0x55, 0x55, 0x55, 0x59, 0x39, 0x54, 0x54, 0x54,
|
||
0x59, 0x39, 0x55, 0x54, 0x54, 0x58, 0x00, 0x00, 0x45, 0x7C, 0x41, 0x00,
|
||
0x02, 0x45, 0x7D, 0x42, 0x00, 0x01, 0x45, 0x7C, 0x40, 0x7D, 0x12, 0x11,
|
||
0x12, 0x7D, // A-umlaut
|
||
0xF0, 0x28, 0x25, 0x28, 0xF0, 0x7C, 0x54, 0x55, 0x45, 0x00, 0x20, 0x54,
|
||
0x54, 0x7C, 0x54, 0x7C, 0x0A, 0x09, 0x7F, 0x49, 0x32, 0x49, 0x49, 0x49,
|
||
0x32, 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut
|
||
0x32, 0x4A, 0x48, 0x48, 0x30, 0x3A, 0x41, 0x41, 0x21, 0x7A, 0x3A, 0x42,
|
||
0x40, 0x20, 0x78, 0x00, 0x9D, 0xA0, 0xA0, 0x7D, 0x3D, 0x42, 0x42, 0x42,
|
||
0x3D, // O-umlaut
|
||
0x3D, 0x40, 0x40, 0x40, 0x3D, 0x3C, 0x24, 0xFF, 0x24, 0x24, 0x48, 0x7E,
|
||
0x49, 0x43, 0x66, 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, 0xFF, 0x09, 0x29, 0xF6,
|
||
0x20, 0xC0, 0x88, 0x7E, 0x09, 0x03, 0x20, 0x54, 0x54, 0x79, 0x41, 0x00,
|
||
0x00, 0x44, 0x7D, 0x41, 0x30, 0x48, 0x48, 0x4A, 0x32, 0x38, 0x40, 0x40,
|
||
0x22, 0x7A, 0x00, 0x7A, 0x0A, 0x0A, 0x72, 0x7D, 0x0D, 0x19, 0x31, 0x7D,
|
||
0x26, 0x29, 0x29, 0x2F, 0x28, 0x26, 0x29, 0x29, 0x29, 0x26, 0x30, 0x48,
|
||
0x4D, 0x40, 0x20, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
|
||
0x38, 0x2F, 0x10, 0xC8, 0xAC, 0xBA, 0x2F, 0x10, 0x28, 0x34, 0xFA, 0x00,
|
||
0x00, 0x7B, 0x00, 0x00, 0x08, 0x14, 0x2A, 0x14, 0x22, 0x22, 0x14, 0x2A,
|
||
0x14, 0x08, 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old
|
||
// code
|
||
0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block
|
||
0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block
|
||
0x00, 0x00, 0x00, 0xFF, 0x00, 0x10, 0x10, 0x10, 0xFF, 0x00, 0x14, 0x14,
|
||
0x14, 0xFF, 0x00, 0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0xF0, 0x10,
|
||
0xF0, 0x14, 0x14, 0x14, 0xFC, 0x00, 0x14, 0x14, 0xF7, 0x00, 0xFF, 0x00,
|
||
0x00, 0xFF, 0x00, 0xFF, 0x14, 0x14, 0xF4, 0x04, 0xFC, 0x14, 0x14, 0x17,
|
||
0x10, 0x1F, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0x1F, 0x00,
|
||
0x10, 0x10, 0x10, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x10, 0x10, 0x10,
|
||
0x10, 0x1F, 0x10, 0x10, 0x10, 0x10, 0xF0, 0x10, 0x00, 0x00, 0x00, 0xFF,
|
||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x00,
|
||
0x00, 0x00, 0xFF, 0x14, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x1F,
|
||
0x10, 0x17, 0x00, 0x00, 0xFC, 0x04, 0xF4, 0x14, 0x14, 0x17, 0x10, 0x17,
|
||
0x14, 0x14, 0xF4, 0x04, 0xF4, 0x00, 0x00, 0xFF, 0x00, 0xF7, 0x14, 0x14,
|
||
0x14, 0x14, 0x14, 0x14, 0x14, 0xF7, 0x00, 0xF7, 0x14, 0x14, 0x14, 0x17,
|
||
0x14, 0x10, 0x10, 0x1F, 0x10, 0x1F, 0x14, 0x14, 0x14, 0xF4, 0x14, 0x10,
|
||
0x10, 0xF0, 0x10, 0xF0, 0x00, 0x00, 0x1F, 0x10, 0x1F, 0x00, 0x00, 0x00,
|
||
0x1F, 0x14, 0x00, 0x00, 0x00, 0xFC, 0x14, 0x00, 0x00, 0xF0, 0x10, 0xF0,
|
||
0x10, 0x10, 0xFF, 0x10, 0xFF, 0x14, 0x14, 0x14, 0xFF, 0x14, 0x10, 0x10,
|
||
0x10, 0x1F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x10, 0xFF, 0xFF, 0xFF, 0xFF,
|
||
0xFF, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
|
||
0x00, 0x00, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x38, 0x44, 0x44,
|
||
0x38, 0x44, 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta
|
||
0x7E, 0x02, 0x02, 0x06, 0x06, 0x02, 0x7E, 0x02, 0x7E, 0x02, 0x63, 0x55,
|
||
0x49, 0x41, 0x63, 0x38, 0x44, 0x44, 0x3C, 0x04, 0x40, 0x7E, 0x20, 0x1E,
|
||
0x20, 0x06, 0x02, 0x7E, 0x02, 0x02, 0x99, 0xA5, 0xE7, 0xA5, 0x99, 0x1C,
|
||
0x2A, 0x49, 0x2A, 0x1C, 0x4C, 0x72, 0x01, 0x72, 0x4C, 0x30, 0x4A, 0x4D,
|
||
0x4D, 0x30, 0x30, 0x48, 0x78, 0x48, 0x30, 0xBC, 0x62, 0x5A, 0x46, 0x3D,
|
||
0x3E, 0x49, 0x49, 0x49, 0x00, 0x7E, 0x01, 0x01, 0x01, 0x7E, 0x2A, 0x2A,
|
||
0x2A, 0x2A, 0x2A, 0x44, 0x44, 0x5F, 0x44, 0x44, 0x40, 0x51, 0x4A, 0x44,
|
||
0x40, 0x40, 0x44, 0x4A, 0x51, 0x40, 0x00, 0x00, 0xFF, 0x01, 0x03, 0xE0,
|
||
0x80, 0xFF, 0x00, 0x00, 0x08, 0x08, 0x6B, 0x6B, 0x08, 0x36, 0x12, 0x36,
|
||
0x24, 0x36, 0x06, 0x0F, 0x09, 0x0F, 0x06, 0x00, 0x00, 0x18, 0x18, 0x00,
|
||
0x00, 0x00, 0x10, 0x10, 0x00, 0x30, 0x40, 0xFF, 0x01, 0x01, 0x00, 0x1F,
|
||
0x01, 0x01, 0x1E, 0x00, 0x19, 0x1D, 0x17, 0x12, 0x00, 0x3C, 0x3C, 0x3C,
|
||
0x3C, 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP
|
||
};
|
||
|
||
// allow clean compilation with [-Wunused-const-variable=] and [-Wall]
|
||
static inline void avoid_unused_const_variable_compiler_warning(void) {
|
||
(void)font;
|
||
}
|
||
|
||
|
||
#define BEEPER_PIN 6
|
||
|
||
//SmartyKit Display Driver parameters
|
||
#define ILI9341_TFTWIDTH 240 ///< ILI9341 max TFT width
|
||
#define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height
|
||
|
||
|
||
//driver commands and parameters
|
||
#define ILI9341_NOP 0x00 ///< No-op register
|
||
#define ILI9341_SWRESET 0x01 ///< Software reset register
|
||
#define ILI9341_RDDID 0x04 ///< Read display identification information
|
||
#define ILI9341_RDDST 0x09 ///< Read Display Status
|
||
|
||
#define ILI9341_SLPIN 0x10 ///< Enter Sleep Mode
|
||
#define ILI9341_SLPOUT 0x11 ///< Sleep Out
|
||
#define ILI9341_PTLON 0x12 ///< Partial Mode ON
|
||
#define ILI9341_NORON 0x13 ///< Normal Display Mode ON
|
||
|
||
#define ILI9341_RDMODE 0x0A ///< Read Display Power Mode
|
||
#define ILI9341_RDMADCTL 0x0B ///< Read Display MADCTL
|
||
#define ILI9341_RDPIXFMT 0x0C ///< Read Display Pixel Format
|
||
#define ILI9341_RDIMGFMT 0x0D ///< Read Display Image Format
|
||
#define ILI9341_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result
|
||
|
||
#define ILI9341_INVOFF 0x20 ///< Display Inversion OFF
|
||
#define ILI9341_INVON 0x21 ///< Display Inversion ON
|
||
#define ILI9341_GAMMASET 0x26 ///< Gamma Set
|
||
#define ILI9341_DISPOFF 0x28 ///< Display OFF
|
||
#define ILI9341_DISPON 0x29 ///< Display ON
|
||
|
||
#define ILI9341_CASET 0x2A ///< Column Address Set
|
||
#define ILI9341_PASET 0x2B ///< Page Address Set
|
||
#define ILI9341_RAMWR 0x2C ///< Memory Write
|
||
#define ILI9341_RAMRD 0x2E ///< Memory Read
|
||
|
||
#define ILI9341_PTLAR 0x30 ///< Partial Area
|
||
#define ILI9341_VSCRDEF 0x33 ///< Vertical Scrolling Definition
|
||
#define ILI9341_MADCTL 0x36 ///< Memory Access Control
|
||
#define ILI9341_VSCRSADD 0x37 ///< Vertical Scrolling Start Address
|
||
#define ILI9341_PIXFMT 0x3A ///< COLMOD: Pixel Format Set
|
||
|
||
#define ILI9341_FRMCTR1 \
|
||
0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors)
|
||
#define ILI9341_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors)
|
||
#define ILI9341_FRMCTR3 \
|
||
0xB3 ///< Frame Rate control (In Partial Mode/Full Colors)
|
||
#define ILI9341_INVCTR 0xB4 ///< Display Inversion Control
|
||
#define ILI9341_DFUNCTR 0xB6 ///< Display Function Control
|
||
|
||
#define ILI9341_PWCTR1 0xC0 ///< Power Control 1
|
||
#define ILI9341_PWCTR2 0xC1 ///< Power Control 2
|
||
#define ILI9341_PWCTR3 0xC2 ///< Power Control 3
|
||
#define ILI9341_PWCTR4 0xC3 ///< Power Control 4
|
||
#define ILI9341_PWCTR5 0xC4 ///< Power Control 5
|
||
#define ILI9341_VMCTR1 0xC5 ///< VCOM Control 1
|
||
#define ILI9341_VMCTR2 0xC7 ///< VCOM Control 2
|
||
|
||
#define ILI9341_RDID1 0xDA ///< Read ID 1
|
||
#define ILI9341_RDID2 0xDB ///< Read ID 2
|
||
#define ILI9341_RDID3 0xDC ///< Read ID 3
|
||
#define ILI9341_RDID4 0xDD ///< Read ID 4
|
||
|
||
#define ILI9341_GMCTRP1 0xE0 ///< Positive Gamma Correction
|
||
#define ILI9341_GMCTRN1 0xE1 ///< Negative Gamma Correction
|
||
//#define ILI9341_PWCTR6 0xFC
|
||
|
||
#define MADCTL_MY 0x80 ///< Bottom to top
|
||
#define MADCTL_MX 0x40 ///< Right to left
|
||
#define MADCTL_MV 0x20 ///< Reverse Mode
|
||
#define MADCTL_NOTMV 0x00 ///< Reverse Mode
|
||
|
||
#define MADCTL_ML 0x10 ///< LCD refresh Bottom to top
|
||
#define MADCTL_RGB 0x00 ///< Red-Green-Blue pixel order
|
||
#define MADCTL_BGR 0x08 ///< Blue-Green-Red pixel order
|
||
#define MADCTL_MH 0x04 ///< LCD refresh right to left
|
||
|
||
// Color definitions
|
||
#define ILI9341_BLACK 0x0000 ///< 0, 0, 0
|
||
#define ILI9341_NAVY 0x000F ///< 0, 0, 123
|
||
#define ILI9341_DARKGREEN 0x03E0 ///< 0, 125, 0
|
||
#define ILI9341_DARKCYAN 0x03EF ///< 0, 125, 123
|
||
#define ILI9341_MAROON 0x7800 ///< 123, 0, 0
|
||
#define ILI9341_PURPLE 0x780F ///< 123, 0, 123
|
||
#define ILI9341_OLIVE 0x7BE0 ///< 123, 125, 0
|
||
#define ILI9341_LIGHTGREY 0xC618 ///< 198, 195, 198
|
||
#define ILI9341_DARKGREY 0x7BEF ///< 123, 125, 123
|
||
#define ILI9341_BLUE 0x001F ///< 0, 0, 255
|
||
#define ILI9341_GREEN 0x07E0 ///< 0, 255, 0
|
||
#define ILI9341_CYAN 0x07FF ///< 0, 255, 255
|
||
#define ILI9341_RED 0xF800 ///< 255, 0, 0
|
||
#define ILI9341_MAGENTA 0xF81F ///< 255, 0, 255
|
||
#define ILI9341_YELLOW 0xFFE0 ///< 255, 255, 0
|
||
#define ILI9341_WHITE 0xFFFF ///< 255, 255, 255
|
||
#define ILI9341_ORANGE 0xFD20 ///< 255, 165, 0
|
||
#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255, 41
|
||
#define ILI9341_PINK 0xFC18 ///< 255, 130, 198
|
||
|
||
// Possible values for SPITFT.connection:
|
||
#define TFT_HARD_SPI 0 ///< Display interface = hardware SPI
|
||
#define TFT_SOFT_SPI 1 ///< Display interface = software SPI
|
||
|
||
|
||
#ifndef _TERMINAL_
|
||
#define TFT_CS A0
|
||
#define TFT_RST A1
|
||
#define TFT_DC A2
|
||
#define TFT_MOSI A3 // 11
|
||
#define TFT_CLK A4 //13
|
||
#define TFT_MISO A5
|
||
|
||
#else
|
||
//so we need to put CS on low, RST = A0, DC = A1, MOSI = A2, SCK = A3, MISO = not connected (NC)
|
||
#define TFT_CS -1
|
||
#define TFT_RST A0
|
||
#define TFT_DC A1
|
||
#define TFT_MOSI A2
|
||
#define TFT_CLK A3
|
||
#define TFT_MISO -1
|
||
#endif
|
||
|
||
|
||
|
||
|
||
#if defined(__AVR__)
|
||
#define DEFAULT_SPI_FREQ 2000000 ///< Hardware SPI default speed
|
||
#else
|
||
#define DEFAULT_SPI_FREQ 4000000L ///< Hardware SPI default speed
|
||
#endif
|
||
|
||
#if defined(__AVR__)
|
||
#define AVR_WRITESPI(x) for (SPDR = (x); (!(SPSR & _BV(SPIF)));)
|
||
#endif
|
||
|
||
#define TFT_TFTwidth 320
|
||
#define TFT_TFTheight 240
|
||
#define SCREEN_COLS 40
|
||
#define SCREEN_ROWS 24
|
||
#define LINE_WIDTH 6
|
||
#define LINE_HEIGHT 8
|
||
#define SCREEN_WIDTH SCREEN_COLS*LINE_WIDTH
|
||
#define SCREEN_HEIGHT SCREEN_ROWS*LINE_HEIGHT
|
||
#define MARGIN_TOP 3*LINE_HEIGHT
|
||
#define MARGIN_BOTTOM 3*LINE_HEIGHT
|
||
#define MARGIN_LEFT (TFT_TFTwidth - SCREEN_COLS*LINE_WIDTH)/2
|
||
#define MARGIN_RIGHT (TFT_TFTwidth - SCREEN_COLS*LINE_WIDTH)/2
|
||
#define SCREEN_TOP MARGIN_TOP
|
||
#define SCREEN_BOTTOM (TFT_TFTheight - MARGIN_BOTTOM)
|
||
#define SCREEN_LEFT MARGIN_LEFT
|
||
#define SCREEN_RIGHT (TFT_TFTwidth - MARGIN_RIGHT)
|
||
#define SCREEN_RECT_MARGIN 3
|
||
|
||
|
||
// clang-format off
|
||
static const uint8_t PROGMEM initcmd[] = {
|
||
0xEF, 3, 0x03, 0x80, 0x02,
|
||
0xCF, 3, 0x00, 0xC1, 0x30, //Power control B (CFh)
|
||
0xED, 4, 0x64, 0x03, 0x12, 0x81, //Power on sequence control (EDh)
|
||
0xE8, 3, 0x85, 0x00, 0x78, //Driver timing control A (E8h) 0xE8, 3, 0x85, 0x00, 0x78,
|
||
0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, //Power control A (CBh)
|
||
0xF7, 1, 0x20, //Pump ratio control (F7h)
|
||
0xEA, 2, 0x00, 0x00, //Driver timing control B (EAh) 0xEA, 2, 0x00, 0x00,
|
||
ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0]
|
||
ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0]
|
||
ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control
|
||
ILI9341_VMCTR2 , 1, 0x86, // VCM control2
|
||
ILI9341_MADCTL , 1, 0x48, // Memory Access Control
|
||
ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero
|
||
ILI9341_PIXFMT , 1, 0x55,
|
||
ILI9341_FRMCTR1 , 2, 0x00, 0x18,
|
||
ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control
|
||
0xF2, 1, 0x00, // 3Gamma Function Disable
|
||
ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected
|
||
ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma
|
||
0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
|
||
ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma
|
||
0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
|
||
ILI9341_SLPOUT , 0x80, // Exit Sleep
|
||
ILI9341_DISPON , 0x80, // Display on
|
||
0x00 // End of list
|
||
};
|
||
// clang-format on
|
||
|
||
|
||
#define TFT_PORTRAIT 1
|
||
#define TFT_LANDSCAPE 0
|
||
|
||
#define CURSOR_RELATIVE 1
|
||
#define CURSOR_ABSOLUTE 0
|
||
|
||
#define SCREEN_FULL_SCREEN 0
|
||
#define SCREEN_CLIPPED 1
|
||
|
||
int tftPortrait = TFT_PORTRAIT;
|
||
//int tftPortrait = TFT_LANDSCAPE;
|
||
|
||
|
||
#undef USE_FAST_PINIO
|
||
|
||
//SmartyKit Display Driver Class members
|
||
class SmartyKit_DisplayDriver
|
||
{
|
||
public:
|
||
SmartyKit_DisplayDriver::SmartyKit_DisplayDriver();
|
||
|
||
SmartyKit_DisplayDriver::~SmartyKit_DisplayDriver()
|
||
{
|
||
if(spiClass)
|
||
spiClass->endTransaction();
|
||
}
|
||
SPIClass *spiClass;
|
||
SPISettings spiSettings;
|
||
int connection;
|
||
int clipScreen;
|
||
uint8_t rotation;
|
||
int16_t _TFTwidth; //full TFT width
|
||
int16_t _TFTheight; //full TFT height
|
||
int16_t _workingScreenWidth; //screen area width: SCREEN_WIDTH
|
||
int16_t _workingScreenHeight; //screen area height: SCREEN_HEIGHT
|
||
int16_t _workingScreenTopMargin;
|
||
int16_t _workingScreenLeftMargin;
|
||
int16_t scrollLine;
|
||
int16_t cursor_x;
|
||
int16_t cursor_y;
|
||
int16_t screen_col;
|
||
int16_t screen_row;
|
||
|
||
int16_t textsize_x;
|
||
int16_t textsize_y;
|
||
int8_t _dc;
|
||
int8_t _rst; ///< Reset pin # (or -1)
|
||
int8_t _cs; ///< Chip select pin # (or -1)
|
||
int8_t _sck;
|
||
int8_t _mosi;
|
||
int8_t _miso;
|
||
|
||
uint16_t color = ILI9341_GREEN;
|
||
uint16_t bgColor = ILI9341_BLACK;
|
||
|
||
|
||
|
||
//functions
|
||
void setup();
|
||
void initSPI(void);
|
||
void sendCommand(uint8_t commandByte, const uint8_t *dataBytes, uint8_t numDataBytes);
|
||
void sendCommand(uint8_t commandByte, uint8_t *dataBytes = 0, uint8_t numDataBytes = 0);
|
||
void spiWrite(uint8_t b); // Write single byte as DATA
|
||
void writeCommand(uint8_t cmd);
|
||
void setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h);
|
||
inline void writeColor(uint16_t color, uint32_t len);
|
||
inline void startWrite(void);
|
||
inline void endWrite(void);
|
||
|
||
void setRotation(uint8_t m);
|
||
void clearFullScreen(uint16_t color = ILI9341_WHITE);
|
||
void clearScreen(void);
|
||
void splashScreen();
|
||
|
||
void drawScreenRect(uint16_t color);
|
||
void drawScreenKeyboard(uint16_t color);
|
||
void drawHLine(uint16_t y, uint16_t color);
|
||
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||
inline void writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||
void scrollTo(uint16_t y);
|
||
void setScrollMargins(uint16_t top, uint16_t bottom);
|
||
void scrollToNextLine(void);
|
||
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size, int keyboard = 0);
|
||
void writePixel(int16_t x, int16_t y, uint16_t color);
|
||
void setCursor(int16_t x, int16_t y, uint8_t relative = CURSOR_RELATIVE);
|
||
void print(uint8_t c, uint16_t color = ILI9341_GREEN);
|
||
|
||
void printScreenBuffer();
|
||
|
||
inline void SPI_BEGIN_TRANSACTION(void){ };
|
||
inline void SPI_END_TRANSACTION(void) { };
|
||
void SPI_DC_HIGH(void);
|
||
void SPI_DC_LOW(void);
|
||
void SPI_CS_HIGH(void);
|
||
void SPI_CS_LOW(void);
|
||
void SPI_WRITE16(uint16_t w);
|
||
//for TFT_SOFT_SPI
|
||
// inline void SPI_MOSI_HIGH(void) { digitalWrite(_mosi, HIGH);};
|
||
// inline void SPI_MOSI_LOW(void) { digitalWrite(_mosi, LOW);};
|
||
// inline void SPI_SCK_HIGH(void) { digitalWrite(_sck, HIGH);};
|
||
// inline void SPI_SCK_LOW(void) { digitalWrite(_sck, LOW);};
|
||
|
||
#ifndef _TERMINAL_
|
||
inline void SPI_MOSI_HIGH(void) { PORTC = PORTC | B001000; }; //MOSI = A3 = PC3
|
||
inline void SPI_MOSI_LOW(void) { PORTC = PORTC & B110111;}; //MOSI = A3 = PC3
|
||
inline void SPI_SCK_HIGH(void) { PORTC = PORTC | B010000;}; //SCK = A4 = PC4
|
||
inline void SPI_SCK_LOW(void) { PORTC = PORTC & B101111;}; //SCK = A4 = PC4
|
||
|
||
|
||
#else
|
||
inline void SPI_MOSI_HIGH(void) { PORTC = PORTC | B000100; }; //MOSI = A2 = PC2
|
||
inline void SPI_MOSI_LOW(void) { PORTC = PORTC & B111011;}; //MOSI = A2 = PC2
|
||
inline void SPI_SCK_HIGH(void) { PORTC = PORTC | B001000;}; //SCK = A3 = PC3
|
||
inline void SPI_SCK_LOW(void) { PORTC = PORTC & B110111;}; //SCK = A3 = PC3
|
||
|
||
#endif
|
||
|
||
|
||
|
||
#if defined(_SMARTY_DEBUG_)
|
||
inline void beep() { tone(BEEPER_PIN, 880, 200); }
|
||
#endif
|
||
|
||
};
|
||
|
||
volatile int screenRow = 0;
|
||
volatile int screenCol = 0;
|
||
char screenBuffer[SCREEN_ROWS][SCREEN_COLS];
|
||
|
||
SmartyKit_DisplayDriver::SmartyKit_DisplayDriver()
|
||
{
|
||
}
|
||
|
||
|
||
void SmartyKit_DisplayDriver::setup()
|
||
{
|
||
// #if defined(_SMARTY_DEBUG_)
|
||
// pinMode(BEEPER_PIN, OUTPUT);
|
||
// #endif
|
||
_dc = TFT_DC;
|
||
_rst = TFT_RST;
|
||
_cs = TFT_CS;
|
||
_sck = TFT_CLK;
|
||
_mosi = TFT_MOSI;
|
||
_miso = TFT_MISO;
|
||
|
||
|
||
//connection = TFT_HARD_SPI;
|
||
connection = TFT_SOFT_SPI;
|
||
|
||
|
||
initSPI();
|
||
|
||
// sendCommand(ILI9341_SWRESET); // Engage software reset
|
||
//delay(200);
|
||
|
||
uint8_t cmd, x, numArgs;
|
||
const uint8_t *addr = initcmd;
|
||
while ((cmd = pgm_read_byte(addr++)) > 0) {
|
||
x = pgm_read_byte(addr++);
|
||
numArgs = x & 0x7F;
|
||
#if defined(_SMARTY_DEBUG_)
|
||
Serial.print(F("Initcmd: cmd = "));Serial.print(cmd, HEX);
|
||
Serial.print(F(", x = "));Serial.print(x, HEX);
|
||
Serial.print(F(", addr = "));Serial.print((uint8_t)addr, HEX);
|
||
Serial.print(F(", numArgs = "));Serial.print(numArgs, HEX);
|
||
Serial.println();
|
||
#endif
|
||
sendCommand(cmd, addr, numArgs);
|
||
delay(10);
|
||
addr += numArgs;
|
||
if (x & 0x80)
|
||
delay(150);
|
||
}
|
||
|
||
clipScreen = SCREEN_FULL_SCREEN;
|
||
scrollLine = 0;
|
||
cursor_x = 0;
|
||
cursor_y = 0;
|
||
textsize_x = 1;
|
||
textsize_y = 1;
|
||
_TFTwidth = ILI9341_TFTWIDTH;
|
||
_TFTheight = ILI9341_TFTHEIGHT;
|
||
_workingScreenWidth = SCREEN_WIDTH;
|
||
_workingScreenHeight = SCREEN_HEIGHT;
|
||
screen_col = 0;
|
||
screen_row = 0;
|
||
|
||
color = ILI9341_GREEN;
|
||
bgColor = ILI9341_BLACK;
|
||
|
||
if (tftPortrait == TFT_PORTRAIT)
|
||
{
|
||
setRotation(0);
|
||
clearFullScreen(ILI9341_BLACK);
|
||
//start right from the top-left corner - TO-DO: move to the screen centers
|
||
_workingScreenTopMargin = 0;
|
||
_workingScreenLeftMargin = 0;
|
||
|
||
// drawScreenRect(ILI9341_WHITE);
|
||
}
|
||
if (tftPortrait == TFT_LANDSCAPE)
|
||
{
|
||
setRotation(3);
|
||
clearFullScreen(ILI9341_BLACK);
|
||
_workingScreenTopMargin = (_TFTheight - SCREEN_ROWS*LINE_HEIGHT)/2;
|
||
_workingScreenLeftMargin = (_TFTwidth - SCREEN_COLS*LINE_WIDTH)/2;
|
||
}
|
||
//drawing splash screen
|
||
splashScreen();
|
||
|
||
if (tftPortrait == TFT_PORTRAIT)
|
||
{
|
||
//set built-in hardware scrolling
|
||
setScrollMargins(0, ILI9341_TFTHEIGHT - SCREEN_HEIGHT);
|
||
clipScreen = SCREEN_CLIPPED;
|
||
|
||
//drawScreenKeyboard(ILI9341_WHITE);
|
||
//drawScreenRect(ILI9341_WHITE);
|
||
|
||
}
|
||
|
||
setCursor(0,0);
|
||
clearScreen();
|
||
print('#');
|
||
print('>');
|
||
|
||
#if defined(_SMARTY_DEBUG_)
|
||
beep();
|
||
#endif
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::initSPI(void)
|
||
{
|
||
|
||
if (_cs >= 0) {
|
||
pinMode(_cs, OUTPUT);
|
||
digitalWrite(_cs, HIGH); // Deselect
|
||
delay(100);
|
||
//digitalWrite(_cs, LOW); // Select
|
||
}
|
||
|
||
pinMode(_dc, OUTPUT);
|
||
digitalWrite(_dc, HIGH); // Data mode
|
||
|
||
if (connection == TFT_HARD_SPI)
|
||
{
|
||
pinMode(SS, OUTPUT);
|
||
// SPI.begin();
|
||
spiClass = &SPI;
|
||
|
||
#if defined(_SMARTY_DEBUG_)
|
||
Serial.print(F("SmartyKit SPI freq = "));Serial.println(DEFAULT_SPI_FREQ, DEC);
|
||
#endif
|
||
|
||
spiSettings = SPISettings(DEFAULT_SPI_FREQ, MSBFIRST, SPI_MODE0);
|
||
spiClass->begin();
|
||
spiClass->beginTransaction(spiSettings);
|
||
pinMode(SS, OUTPUT);
|
||
}
|
||
else if (connection == TFT_SOFT_SPI)
|
||
{
|
||
pinMode(_mosi, OUTPUT);
|
||
digitalWrite(_mosi, LOW);
|
||
pinMode(_sck, OUTPUT);
|
||
digitalWrite(_sck, LOW);
|
||
if (_miso >= 0) {
|
||
pinMode(_miso, INPUT);
|
||
}
|
||
}
|
||
|
||
|
||
if (_rst >= 0) {
|
||
// Toggle _rst low to reset
|
||
pinMode(_rst, OUTPUT);
|
||
digitalWrite(_rst, HIGH);
|
||
delay(100);
|
||
digitalWrite(_rst, LOW);
|
||
delay(100);
|
||
digitalWrite(_rst, HIGH);
|
||
delay(200);
|
||
}
|
||
}
|
||
|
||
inline void SmartyKit_DisplayDriver::startWrite(void) {
|
||
SPI_BEGIN_TRANSACTION();
|
||
if (_cs >= 0)
|
||
SPI_CS_LOW();
|
||
}
|
||
|
||
inline void SmartyKit_DisplayDriver::endWrite(void) {
|
||
if (_cs >= 0)
|
||
SPI_CS_HIGH();
|
||
SPI_END_TRANSACTION();
|
||
}
|
||
void SmartyKit_DisplayDriver::setCursor(int16_t x, int16_t y, uint8_t relative = CURSOR_RELATIVE) {
|
||
if (relative == CURSOR_RELATIVE)
|
||
{
|
||
cursor_x = _workingScreenLeftMargin + x;
|
||
cursor_y = _workingScreenTopMargin + y;
|
||
}
|
||
else if (relative == CURSOR_ABSOLUTE)
|
||
{
|
||
cursor_x = x;
|
||
cursor_y = y;
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::splashScreen()
|
||
{
|
||
int logoWidth = 19;
|
||
//draw Smarty logo in the center
|
||
if (rotation == 0 || rotation == 3)
|
||
{
|
||
startWrite();
|
||
setAddrWindow(_TFTwidth / 2 - logoWidth/2, _TFTheight / 2 - logoWidth/2, logoWidth, logoWidth);
|
||
//draw bgColor line to erase
|
||
for (uint16_t i = 0; i < logoWidth; i++)
|
||
{
|
||
for (int x = 0; x < logoWidth; x++)
|
||
SPI_WRITE16(ILI9341_WHITE);
|
||
}
|
||
//endWrite();
|
||
|
||
int logoInnerWidth = logoWidth/2;
|
||
//draw Smarty logo in the center
|
||
//startWrite();
|
||
setAddrWindow(_TFTwidth / 2 - logoInnerWidth/2, _TFTheight / 2 - logoInnerWidth/2, logoInnerWidth, logoInnerWidth);
|
||
//draw bgColor line to erase
|
||
for (uint16_t i = 0; i < logoInnerWidth; i++)
|
||
{
|
||
for (int x = 0; x < logoInnerWidth; x++)
|
||
SPI_WRITE16(ILI9341_BLACK);
|
||
}
|
||
endWrite();
|
||
|
||
//delay(5000);
|
||
|
||
delay(1500);
|
||
|
||
//print company name
|
||
int chars = 24;
|
||
char company[chars] = "Made with \x03 by SmartyKit";
|
||
//char company[chars] = "MADE WITH \x03 BY SMARTYKIT, INC.";
|
||
|
||
setCursor(_TFTwidth / 2 - (chars*LINE_WIDTH)/2, _TFTheight - LINE_HEIGHT- 4, CURSOR_ABSOLUTE);
|
||
for (int i = 0; i < chars; i++)
|
||
{
|
||
if (company[i] == '\x03') //heart
|
||
print(company[i], ILI9341_RED);
|
||
else
|
||
print(company[i], ILI9341_WHITE);
|
||
delay(100);
|
||
}
|
||
|
||
delay(1500);
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::sendCommand(uint8_t commandByte, const uint8_t *dataBytes,
|
||
uint8_t numDataBytes) {
|
||
SPI_BEGIN_TRANSACTION();
|
||
if (_cs >= 0)
|
||
SPI_CS_LOW();
|
||
|
||
#if defined(_SMARTY_DEBUG_)
|
||
Serial.print(F("PGM -> "));
|
||
#endif
|
||
|
||
SPI_DC_LOW(); // Command mode
|
||
spiWrite(commandByte); // Send the command byte
|
||
|
||
SPI_DC_HIGH();
|
||
for (int i = 0; i < numDataBytes; i++) {
|
||
Serial.print(F("arg")); Serial.print(i+1, DEC); Serial.print(F(" = "));
|
||
uint8_t dataByte = pgm_read_byte(dataBytes++);
|
||
dataByte &= 0xFF;
|
||
spiWrite(dataByte);
|
||
}
|
||
|
||
if (_cs >= 0)
|
||
SPI_CS_HIGH();
|
||
SPI_END_TRANSACTION();
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::sendCommand(uint8_t commandByte, uint8_t *dataBytes,
|
||
uint8_t numDataBytes) {
|
||
SPI_BEGIN_TRANSACTION();
|
||
if (_cs >= 0)
|
||
SPI_CS_LOW();
|
||
|
||
SPI_DC_LOW(); // Command mode
|
||
spiWrite(commandByte); // Send the command byte
|
||
|
||
SPI_DC_HIGH();
|
||
for (int i = 0; i < numDataBytes; i++) {
|
||
spiWrite(*dataBytes); // Send the data bytes
|
||
dataBytes++;
|
||
}
|
||
if (_cs >= 0)
|
||
SPI_CS_HIGH();
|
||
SPI_END_TRANSACTION();
|
||
}
|
||
|
||
//Set the data/command line HIGH (data mode).
|
||
void SmartyKit_DisplayDriver::SPI_DC_HIGH(void) {
|
||
#if defined(USE_FAST_PINIO)
|
||
|
||
#else // !USE_FAST_PINIO
|
||
digitalWrite(_dc, HIGH);
|
||
#endif // end !USE_FAST_PINIO
|
||
}
|
||
|
||
//Set the data/command line LOW (command mode).
|
||
void SmartyKit_DisplayDriver::SPI_DC_LOW(void) {
|
||
#if defined(USE_FAST_PINIO)
|
||
|
||
#else // !USE_FAST_PINIO
|
||
digitalWrite(_dc, LOW);
|
||
#endif // end !USE_FAST_PINIO
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::SPI_CS_LOW(void) {
|
||
#if defined(USE_FAST_PINIO)
|
||
|
||
#else // !USE_FAST_PINIO
|
||
digitalWrite(_cs, LOW);
|
||
#endif // end !USE_FAST_PINIO
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::SPI_CS_HIGH(void) {
|
||
#if defined(USE_FAST_PINIO)
|
||
|
||
#else // !USE_FAST_PINIO
|
||
digitalWrite(_cs, HIGH);
|
||
#endif // end !USE_FAST_PINIO
|
||
}
|
||
|
||
|
||
void SmartyKit_DisplayDriver::spiWrite(uint8_t b) {
|
||
if (connection == TFT_HARD_SPI) {
|
||
#if defined(__AVR__)
|
||
AVR_WRITESPI(b);
|
||
#else
|
||
char c = spiClass->transfer(b);
|
||
#if defined(_SMARTY_DEBUG_)
|
||
Serial.print(F("spiWrite = "));Serial.println(c, HEX);
|
||
#endif
|
||
#endif
|
||
} else if (connection == TFT_SOFT_SPI)
|
||
{
|
||
for (uint8_t bit = 0; bit < 8; bit++) {
|
||
if (b & 0x80)
|
||
SPI_MOSI_HIGH();
|
||
else
|
||
SPI_MOSI_LOW();
|
||
SPI_SCK_HIGH();
|
||
b <<= 1;
|
||
SPI_SCK_LOW();
|
||
}
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::writeCommand(uint8_t cmd) {
|
||
SPI_DC_LOW();
|
||
spiWrite(cmd);
|
||
SPI_DC_HIGH();
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::setRotation(uint8_t m) {
|
||
rotation = m % 4; // can't be higher than 3
|
||
switch (rotation) {
|
||
case 0:
|
||
m = (MADCTL_MX | MADCTL_BGR);
|
||
_TFTwidth = ILI9341_TFTWIDTH;
|
||
_TFTheight = ILI9341_TFTHEIGHT;
|
||
break;
|
||
case 1:
|
||
m = (MADCTL_MV | MADCTL_BGR);
|
||
_TFTwidth = ILI9341_TFTHEIGHT;
|
||
_TFTheight = ILI9341_TFTWIDTH;
|
||
break;
|
||
case 2:
|
||
m = (MADCTL_MY | MADCTL_BGR);
|
||
_TFTwidth = ILI9341_TFTWIDTH;
|
||
_TFTheight = ILI9341_TFTHEIGHT;
|
||
break;
|
||
case 3:
|
||
// m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
||
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
|
||
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_ML | MADCTL_MH | MADCTL_BGR);
|
||
_TFTwidth = ILI9341_TFTHEIGHT;
|
||
_TFTheight = ILI9341_TFTWIDTH;
|
||
break;
|
||
}
|
||
|
||
sendCommand(ILI9341_MADCTL, &m, 1);
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::clearFullScreen(uint16_t color = ILI9341_WHITE)
|
||
{
|
||
startWrite();
|
||
setAddrWindow(0, 0, _TFTwidth, _TFTheight);
|
||
for (int y = 0; y < _TFTheight; y++)
|
||
{
|
||
|
||
for (int x = 0; x < _TFTwidth; x++)
|
||
{
|
||
//setAddrWindow(x, y, 1, 1);
|
||
SPI_WRITE16(color);
|
||
}
|
||
}
|
||
endWrite();
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::clearScreen(void)
|
||
{
|
||
if (rotation == 3)
|
||
{
|
||
uint16_t color = ILI9341_BLACK;
|
||
uint16_t color2 = ILI9341_BLACK;
|
||
startWrite();
|
||
setAddrWindow(_workingScreenLeftMargin, _workingScreenTopMargin, _workingScreenWidth, _workingScreenHeight);
|
||
for (int y = 0; y < _workingScreenHeight; y++)
|
||
{
|
||
for (int x = 0; x < _workingScreenWidth; x++)
|
||
{
|
||
//setAddrWindow(x, y, 1, 1);
|
||
if (y % 2 == 0)
|
||
SPI_WRITE16(color);
|
||
else
|
||
SPI_WRITE16(color2);
|
||
}
|
||
}
|
||
endWrite();
|
||
}
|
||
else if (rotation == 0)
|
||
{
|
||
uint16_t color = ILI9341_BLACK;
|
||
uint16_t color2 = ILI9341_BLACK;
|
||
startWrite();
|
||
setAddrWindow(_workingScreenLeftMargin, _workingScreenTopMargin, _workingScreenWidth, _workingScreenHeight);
|
||
for (int y = 0; y < _workingScreenHeight; y++)
|
||
{
|
||
for (int x = 0; x < _workingScreenWidth; x++)
|
||
{
|
||
//setAddrWindow(x, y, 1, 1);
|
||
if (y % 2 == 0)
|
||
SPI_WRITE16(color);
|
||
else
|
||
SPI_WRITE16(color2);
|
||
}
|
||
}
|
||
endWrite();
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::scrollTo(uint16_t y) {
|
||
|
||
int scroll = y;
|
||
if (y > SCREEN_HEIGHT)
|
||
scroll = SCREEN_HEIGHT;
|
||
|
||
startWrite();
|
||
setAddrWindow(0, 0, SCREEN_WIDTH, scroll);
|
||
//draw bgColor line to erase
|
||
for (uint16_t i = 0; i < scroll; i++)
|
||
{
|
||
for (int x = 0; x < SCREEN_WIDTH; x++)
|
||
SPI_WRITE16(bgColor);
|
||
}
|
||
endWrite();
|
||
//scroll screen
|
||
uint8_t data[2];
|
||
data[0] = (y) >> 8;
|
||
data[1] = (y) & 0xff;
|
||
sendCommand(ILI9341_VSCRSADD, (uint8_t *)data, 2);
|
||
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::drawScreenRect(uint16_t color)
|
||
{
|
||
if (rotation == 0 || rotation == 3)
|
||
{
|
||
startWrite();
|
||
setAddrWindow(_workingScreenLeftMargin, _workingScreenTopMargin + _workingScreenHeight, _workingScreenWidth, 1);
|
||
for (int x = 0; x < _workingScreenWidth; x++)
|
||
SPI_WRITE16(color);
|
||
endWrite();
|
||
}
|
||
}
|
||
|
||
|
||
void SmartyKit_DisplayDriver::drawScreenKeyboard(uint16_t color)
|
||
{
|
||
int kbdRows = 5;
|
||
int kbdCols = 13;
|
||
int kbdTextSize = 2;
|
||
char kbd[kbdRows][kbdCols] = {
|
||
{'!','@','#','$','%','^', '&', '*', '(', ')', '_', '+', '<',},
|
||
{'1','2','3','4','5', '6', '7', '8', '9', '0', '-', '=', '>',},
|
||
{'Q','W','E','R','T','Y', 'U', 'I', 'O', 'P', ':', '[', ']',},
|
||
{'A','S','D','F','G','H', 'J', 'K', 'L', ';', '"', '\'', '\\', },
|
||
{'Z','X','C','V','B','N', 'M', '\x205', '\x245', '\x244', 'E', ',', '.', },
|
||
};
|
||
uint16_t kbdColor = ILI9341_WHITE;
|
||
int kbdMargin = 5;
|
||
int kbdMarginH = 6;
|
||
int kbdMarginV = 2;
|
||
|
||
int keyboardHeight = kbdRows*LINE_HEIGHT + (kbdRows - 1)*kbdMargin;
|
||
|
||
int kbdX = _workingScreenLeftMargin + LINE_WIDTH*kbdTextSize/2;
|
||
int kbdY = _workingScreenTopMargin + _workingScreenHeight + kbdMarginH;
|
||
// if (rotation == 0)
|
||
// {
|
||
// startWrite();
|
||
// setAddrWindow(kbbX, kbdY, _workingScreenWidth, keyboardHeight);
|
||
// for (int x = 0; x < _workingScreenWidth*keyboardHeight; x++)
|
||
// SPI_WRITE16(kbdColor);
|
||
// endWrite();
|
||
// }
|
||
for (int i = 0; i < kbdRows; i++)
|
||
{
|
||
for (int j = 0; j < kbdCols; j++)
|
||
{
|
||
drawChar(kbdX + j*(LINE_WIDTH*kbdTextSize + kbdMarginH), kbdY + i*(LINE_HEIGHT*kbdTextSize+kbdMarginV), kbd[i][j],
|
||
ILI9341_BLACK, ILI9341_WHITE, kbdTextSize, 1);
|
||
//drawChar(cursor_x, yLine, c, color, bgColor, textsize_x);
|
||
}
|
||
}
|
||
|
||
//draw Space bar, Enter and Delete
|
||
int buttonsX = kbdX;
|
||
int buttonsY = kbdY + kbdRows*(LINE_HEIGHT*kbdTextSize+kbdMarginV);
|
||
int spaceCols = 6;
|
||
int spaceWidth = spaceCols*kbdTextSize*LINE_WIDTH + (spaceCols - 1)*kbdMarginH;
|
||
writeFillRect(buttonsX, buttonsY, spaceWidth, kbdTextSize * LINE_HEIGHT, ILI9341_WHITE);
|
||
|
||
int enterCols = 3;
|
||
int enterWidth = enterCols*kbdTextSize*LINE_WIDTH + (enterCols - 1)*kbdMarginH;
|
||
writeFillRect(buttonsX + spaceWidth + kbdMarginH, buttonsY, enterWidth, kbdTextSize * LINE_HEIGHT, ILI9341_WHITE);
|
||
|
||
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::drawHLine(uint16_t y, uint16_t color)
|
||
{
|
||
//converting screen coordinates to memory coordinates
|
||
int yLine;
|
||
if ((scrollLine + y) < SCREEN_HEIGHT)
|
||
yLine = scrollLine + y;
|
||
else
|
||
yLine = (scrollLine + y) - SCREEN_HEIGHT;
|
||
|
||
if (rotation == 0)
|
||
{
|
||
startWrite();
|
||
setAddrWindow(0, yLine, SCREEN_WIDTH, 1);
|
||
for (int x = 0; x < SCREEN_WIDTH; x++)
|
||
{
|
||
SPI_WRITE16(color);
|
||
}
|
||
endWrite();
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::setScrollMargins(uint16_t top, uint16_t bottom) {
|
||
// TFA+VSA+BFA must equal 320
|
||
if (top + bottom <= ILI9341_TFTHEIGHT) {
|
||
uint16_t middle = ILI9341_TFTHEIGHT - top - bottom;
|
||
uint8_t data[6];
|
||
data[0] = top >> 8;
|
||
data[1] = top & 0xff;
|
||
data[2] = middle >> 8;
|
||
data[3] = middle & 0xff;
|
||
data[4] = bottom >> 8;
|
||
data[5] = bottom & 0xff;
|
||
sendCommand(ILI9341_VSCRDEF, (uint8_t *)data, 6);
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::scrollToNextLine(void)
|
||
{
|
||
if (rotation == 0 || rotation == 3) //build-in hardware scroll
|
||
{
|
||
//TO-DO: add margins - left and top
|
||
startWrite();
|
||
setAddrWindow(0, scrollLine, _workingScreenWidth, LINE_HEIGHT);
|
||
//draw bgColor line to erase
|
||
for (uint16_t i = 0; i < LINE_HEIGHT; i++)
|
||
{
|
||
for (int x = 0; x < SCREEN_WIDTH; x++)
|
||
SPI_WRITE16(bgColor);
|
||
}
|
||
endWrite();
|
||
|
||
if ((scrollLine + LINE_HEIGHT) < SCREEN_HEIGHT)
|
||
scrollLine += LINE_HEIGHT;
|
||
else
|
||
scrollLine = (scrollLine + LINE_HEIGHT) - SCREEN_HEIGHT;
|
||
|
||
//scroll screen
|
||
uint8_t data[2];
|
||
data[0] = (scrollLine) >> 8;
|
||
data[1] = (scrollLine) & 0xff;
|
||
sendCommand(ILI9341_VSCRSADD, (uint8_t *)data, 2);
|
||
}
|
||
// else if (rotation == 3)
|
||
// {
|
||
// clearScreen();
|
||
// //2 - shift text buffer for 1 line
|
||
// scrollScreenBuffer(1);
|
||
// //3 - redraw text from buffer
|
||
// printScreenBuffer();
|
||
// }
|
||
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w,
|
||
uint16_t h) {
|
||
uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1);
|
||
writeCommand(ILI9341_CASET); // Column address set
|
||
SPI_WRITE16(x1);
|
||
SPI_WRITE16(x2);
|
||
writeCommand(ILI9341_PASET); // Row address set
|
||
SPI_WRITE16(y1);
|
||
SPI_WRITE16(y2);
|
||
writeCommand(ILI9341_RAMWR); // Write to RAM
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::SPI_WRITE16(uint16_t w) {
|
||
if (connection == TFT_HARD_SPI) {
|
||
#if defined(__AVR__)
|
||
AVR_WRITESPI(w >> 8);
|
||
AVR_WRITESPI(w);
|
||
#endif
|
||
|
||
// char c = spiClass->transfer((uint8_t)w >> 8);
|
||
// #if defined(_SMARTY_DEBUG_)
|
||
// Serial.print(F("SPI_WRIE16 High = "));Serial.print(c, HEX);
|
||
// #endif
|
||
// c = spiClass->transfer((uint8_t)w);
|
||
// #if defined(_SMARTY_DEBUG_)
|
||
// Serial.print(F(", Low = "));Serial.println(c, HEX);
|
||
// #endif
|
||
} else if (connection == TFT_SOFT_SPI) {
|
||
for (uint8_t bit = 0; bit < 16; bit++) {
|
||
if (w & 0x8000)
|
||
SPI_MOSI_HIGH();
|
||
else
|
||
SPI_MOSI_LOW();
|
||
SPI_SCK_HIGH();
|
||
SPI_SCK_LOW();
|
||
w <<= 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size, int keyboard = 0)
|
||
{
|
||
uint8_t size_x = size;
|
||
uint8_t size_y = size;
|
||
|
||
if ((x >= _TFTwidth) || // Clip right
|
||
(y >= _TFTheight) || // Clip bottom
|
||
((x + 6 * size_x - 1) < 0) || // Clip left
|
||
((y + 8 * size_y - 1) < 0)) // Clip top
|
||
{
|
||
// Serial.print(F("drawChar: clipping -> x = ")); Serial.print(x, DEC); Serial.print(F(", y = ")); Serial.print(y, DEC);
|
||
// Serial.print(F(", _TFTheight = ")); Serial.print(_TFTheight, DEC); Serial.println();
|
||
return;
|
||
}
|
||
// if (!_cp437 && (c >= 176))
|
||
// c++; // Handle 'classic' charset behavior
|
||
startWrite();
|
||
//add first h-line for keyboard
|
||
if(keyboard == 1)
|
||
{
|
||
writeFillRect(x-2, y - 1, size_x*6+2, size_y, bg);
|
||
}
|
||
|
||
for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns
|
||
uint8_t line = pgm_read_byte(&font[c * 5 + i]);
|
||
|
||
for (int8_t j = 0; j < 8; j++, line >>= 1) {
|
||
if (line & 1) {
|
||
if (size_x == 1 && size_y == 1)
|
||
writePixel(x + i, y + j, color);
|
||
else
|
||
writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y,
|
||
color);
|
||
} else if (bg != color) {
|
||
if (size_x == 1 && size_y == 1)
|
||
writePixel(x + i, y + j, bg);
|
||
else
|
||
writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bg != color) { // If opaque, draw vertical line for last column
|
||
if (size_x == 1 && size_y == 1)
|
||
writeFastVLine(x + 5, y, 8, bg);
|
||
else
|
||
writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg);
|
||
|
||
//add first v-line for keyboard
|
||
if(keyboard == 1)
|
||
{
|
||
if (size_x == 1 && size_y == 1)
|
||
writeFastVLine(x - 2, y, 8, bg);
|
||
else
|
||
writeFillRect(x - 1*size_x, y, size_x, 8 * size_y, bg);
|
||
}
|
||
}
|
||
|
||
endWrite();
|
||
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::print(uint8_t c, uint16_t color = ILI9341_GREEN)
|
||
{
|
||
|
||
if (c == '\n') { // Newline?
|
||
cursor_x = _workingScreenLeftMargin; // Reset x to zero,
|
||
cursor_y += textsize_y * 8; // advance y one line
|
||
//screen_col = 0;
|
||
|
||
int maxHeight = _TFTheight;
|
||
if (clipScreen == SCREEN_CLIPPED)
|
||
maxHeight = _workingScreenHeight + _workingScreenTopMargin;
|
||
if (cursor_y >= maxHeight )
|
||
{
|
||
scrollToNextLine();
|
||
cursor_y -= textsize_y * 8;
|
||
//screen_row = SCREEN_ROWS - 1;
|
||
}
|
||
// else
|
||
// screen_row++;
|
||
|
||
} else if (c != '\r') { // Ignore carriage returns
|
||
if ((cursor_x + textsize_x * 6) > _workingScreenLeftMargin + _workingScreenWidth) { // Off right?
|
||
cursor_x = _workingScreenLeftMargin; // Reset x to zero,
|
||
// screen_col = 0;
|
||
cursor_y += textsize_y * 8; // advance y one line
|
||
}
|
||
|
||
//autoscroll mode
|
||
int maxHeight = _TFTheight;
|
||
if (clipScreen == SCREEN_CLIPPED)
|
||
maxHeight = _workingScreenHeight + _workingScreenTopMargin;
|
||
if (cursor_y >= maxHeight)
|
||
{
|
||
scrollToNextLine();
|
||
cursor_y -= textsize_y * 8;
|
||
// screen_row = SCREEN_ROWS - 1;
|
||
}
|
||
// else
|
||
// screen_row++;
|
||
|
||
//converting screen coordinates to memory coordinates
|
||
int yLine;
|
||
if ((scrollLine + cursor_y) < maxHeight)
|
||
yLine = scrollLine + cursor_y;
|
||
else
|
||
yLine = (scrollLine + cursor_y) - maxHeight;
|
||
|
||
drawChar(cursor_x, yLine, c, color, bgColor, textsize_x);
|
||
cursor_x += textsize_x * 6; // Advance x one char
|
||
// screen_col++;
|
||
// screenBuffer[screen_row][screen_col] = c;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
|
||
void SmartyKit_DisplayDriver::writePixel(int16_t x, int16_t y, uint16_t color)
|
||
{
|
||
// Clip first...
|
||
if ((x >= 0) && (x < _TFTwidth) && (y >= 0) && (y < _TFTheight)) {
|
||
// THEN set up transaction (if needed) and draw...
|
||
startWrite();
|
||
setAddrWindow(x, y, 1, 1);
|
||
SPI_WRITE16(color);
|
||
endWrite();
|
||
|
||
// //save for screen buffer
|
||
// int col = x / LINE_WIDTH;
|
||
// int mask = (1 << (x % LINE_WIDTH)) - 1;
|
||
// if (color == ILI9341_BLACK)
|
||
// mask &= B00000000;
|
||
// else if (color == ILI9341_GREEN)
|
||
// mask |= B11111111;
|
||
//
|
||
// pixelBuffer[x][y] = pixelBuffer[x][y] || mask;
|
||
|
||
}
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
||
{
|
||
if ((x >= 0) && (x < _TFTwidth) && h) { // X on screen, nonzero height
|
||
if (h < 0) { // If negative height...
|
||
y += h + 1; // Move Y to top edge
|
||
h = -h; // Use positive height
|
||
}
|
||
if (y < _TFTheight) { // Not off bottom
|
||
int16_t y2 = y + h - 1;
|
||
if (y2 >= 0) { // Not off top
|
||
// Line partly or fully overlaps screen
|
||
if (y < 0) {
|
||
y = 0;
|
||
h = y2 + 1;
|
||
} // Clip top
|
||
if (y2 >= _TFTheight) {
|
||
h = _TFTheight - y;
|
||
} // Clip bottom
|
||
writeFillRectPreclipped(x, y, 1, h, color);
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
void SmartyKit_DisplayDriver::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
||
{
|
||
if (w && h) { // Nonzero width and height?
|
||
if (w < 0) { // If negative width...
|
||
x += w + 1; // Move X to left edge
|
||
w = -w; // Use positive width
|
||
}
|
||
if (x < _TFTwidth) { // Not off right
|
||
if (h < 0) { // If negative height...
|
||
y += h + 1; // Move Y to top edge
|
||
h = -h; // Use positive height
|
||
}
|
||
if (y < _TFTheight) { // Not off bottom
|
||
int16_t x2 = x + w - 1;
|
||
if (x2 >= 0) { // Not off left
|
||
int16_t y2 = y + h - 1;
|
||
if (y2 >= 0) { // Not off top
|
||
// Rectangle partly or fully overlaps screen
|
||
if (x < 0) {
|
||
x = 0;
|
||
w = x2 + 1;
|
||
} // Clip left
|
||
if (y < 0) {
|
||
y = 0;
|
||
h = y2 + 1;
|
||
} // Clip top
|
||
if (x2 >= _TFTwidth) {
|
||
w = _TFTwidth - x;
|
||
} // Clip right
|
||
if (y2 >= _TFTheight) {
|
||
h = _TFTheight - y;
|
||
} // Clip bottom
|
||
writeFillRectPreclipped(x, y, w, h, color);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
inline void SmartyKit_DisplayDriver::writeFillRectPreclipped(int16_t x, int16_t y,
|
||
int16_t w, int16_t h,
|
||
uint16_t color) {
|
||
startWrite();
|
||
setAddrWindow(x, y, w, h);
|
||
writeColor(color, (uint32_t)w * h);
|
||
endWrite();
|
||
}
|
||
|
||
void SmartyKit_DisplayDriver::printScreenBuffer()
|
||
{
|
||
int cursor_x = _workingScreenLeftMargin;
|
||
int cursor_y = _workingScreenTopMargin;
|
||
setCursor(0, 0); //top-left of working screen
|
||
for (int i = 0; i < SCREEN_ROWS; i++)
|
||
{
|
||
for (int j = 0; j < SCREEN_COLS; j++)
|
||
{
|
||
|
||
char c = screenBuffer[i][j];
|
||
|
||
if (c == '\n') { // Newline?
|
||
cursor_x = _workingScreenLeftMargin; // Reset x to zero,
|
||
cursor_y += textsize_y * 8; // advance y one line
|
||
|
||
int maxHeight = _TFTheight;
|
||
if (clipScreen == SCREEN_CLIPPED)
|
||
maxHeight = _workingScreenHeight + _workingScreenTopMargin;
|
||
if (cursor_y >= maxHeight )
|
||
{
|
||
scrollToNextLine();
|
||
cursor_y -= textsize_y * 8;
|
||
}
|
||
|
||
} else if (c != '\r') { // Ignore carriage returns
|
||
if ((cursor_x + textsize_x * 6) > _workingScreenLeftMargin + _workingScreenWidth) { // Off right?
|
||
cursor_x = _workingScreenLeftMargin; // Reset x to zero,
|
||
cursor_y += textsize_y * 8; // advance y one line
|
||
}
|
||
|
||
//autoscroll mode
|
||
int maxHeight = _TFTheight;
|
||
if (clipScreen == SCREEN_CLIPPED)
|
||
maxHeight = _workingScreenHeight + _workingScreenTopMargin;
|
||
if (cursor_y >= maxHeight)
|
||
{
|
||
scrollToNextLine();
|
||
cursor_y -= textsize_y * 8;
|
||
}
|
||
|
||
//converting screen coordinates to memory coordinates
|
||
int yLine;
|
||
if ((scrollLine + cursor_y) < maxHeight)
|
||
yLine = scrollLine + cursor_y;
|
||
else
|
||
yLine = (scrollLine + cursor_y) - maxHeight;
|
||
|
||
drawChar(cursor_x, yLine, c, color, bgColor, textsize_x);
|
||
cursor_x += textsize_x * 6; // Advance x one char
|
||
|
||
//screenBuffer
|
||
}
|
||
}
|
||
}
|
||
print('\n');
|
||
}
|
||
|
||
inline void SmartyKit_DisplayDriver::writeColor(uint16_t color, uint32_t len)
|
||
{
|
||
for (uint16_t i = 0; i < len; i++)
|
||
SPI_WRITE16(color);
|
||
}
|
||
//end: SmartyKit Display Driver Class
|
||
|
||
// 40 keys 4x10 Keyboard Driver Class
|
||
class SmartyKit_40KeysKeyboardDriver
|
||
{
|
||
public:
|
||
int colPressed;
|
||
int rowPressed;
|
||
const static int numRows = 4;
|
||
const static int numCols = 10;
|
||
int rowPins[numRows] = {0,1,2,3};
|
||
int colPins[numCols] = {4,5,6,7,8,9,10,11,12,13};
|
||
|
||
char kbdTable[numRows][numCols] = {
|
||
{'1','2','3','4','5', '6', '7', '8', '9', '0',},
|
||
{'Q','W','E','R','T','Y', 'U', 'I', 'O', 'P',},
|
||
{'A','S','D','F','G','H', 'J', 'K', 'L', '\n', },
|
||
{'\xE','Z', 'X','C','V','B','N', 'M', '\x20', '\x7F',},
|
||
};
|
||
|
||
|
||
SmartyKit_40KeysKeyboardDriver::SmartyKit_40KeysKeyboardDriver(){};
|
||
SmartyKit_40KeysKeyboardDriver::~SmartyKit_40KeysKeyboardDriver(){};
|
||
|
||
void setup()
|
||
{
|
||
//setup
|
||
for (int row = 0; row < numRows; row++)
|
||
pinMode(rowPins[row], INPUT_PULLUP);
|
||
|
||
for (int col = 0; col < numCols; col++)
|
||
{
|
||
pinMode(colPins[col], OUTPUT);
|
||
digitalWrite(colPins[col], HIGH);
|
||
}
|
||
}
|
||
|
||
char read()
|
||
{
|
||
char c = '\x0';
|
||
|
||
|
||
int val = 0;
|
||
|
||
for (int col = 0; col < numCols; col++)
|
||
{
|
||
//searching with col = LOW
|
||
digitalWrite(colPins[col], LOW);
|
||
|
||
for (int row = 0; row < numRows; row++)
|
||
{
|
||
val = digitalRead(rowPins[row]);
|
||
if (val == LOW)
|
||
{
|
||
c = kbdTable[row][col];
|
||
colPressed = col;
|
||
rowPressed = row;
|
||
}
|
||
}
|
||
digitalWrite(colPins[col], HIGH);
|
||
}
|
||
// c = kbdTable[3][7];
|
||
return c;
|
||
}
|
||
};
|
||
//end: 40 keys 4x10 Keyboard Driver Class
|
||
|
||
|
||
/**********************************************************************/
|
||
/**********************************************************************/
|
||
/**********************************************************************/
|
||
/**********************************************************************/
|
||
/**********************************************************************/
|
||
|
||
//main code: setup() and loop()
|
||
SmartyKit_40KeysKeyboardDriver kbd;
|
||
SmartyKit_DisplayDriver tft; //creating instance of our Display Driver
|
||
|
||
|
||
|
||
const int CPUwritesToVideoPortPin = 3;
|
||
const int VideoBIT7pin = 5;
|
||
int DataBus[8] = {6, 7, 8, 9, 10, 11, 12, 13};
|
||
byte scan_code=0;
|
||
|
||
void setup() {
|
||
pinMode(VideoBIT7pin, OUTPUT);
|
||
digitalWrite(VideoBIT7pin, HIGH); //wait until video setup is ready
|
||
|
||
// starting TFT screen
|
||
tft.setup();
|
||
|
||
for (int count = 1; count <= 8; count++) {
|
||
pinMode(DataBus[count-1], INPUT);
|
||
};
|
||
pinMode(CPUwritesToVideoPortPin, INPUT);
|
||
|
||
#ifdef _TERMINAL_
|
||
// Initialise the terminal
|
||
//term.cursorOff();
|
||
// show hello world
|
||
term.setFont(TERMINAL_FONT_40_NORMAL_SINGLE);
|
||
term.setCursor(0,0);
|
||
term.printLine("Hello!\r\nI'm SmartyKit 1\r\nApple 1-compatible computer\r\nwww.smartykit.io\n");
|
||
|
||
term.printLine("\nType address to run:");
|
||
term.printLine("F000R -> Woz's face demo");
|
||
|
||
term.printLine("");
|
||
term.printLine(" 40x25 text output library for Arduino in two wire interface (I" "\xFD" "C) Mode");
|
||
term.printLine("");
|
||
// Show the 80 character positions
|
||
term.print("00000000001111111111222222222233333333334444444444555555555566666666667777777777");
|
||
term.printLine("01234567890123456789012345678901234567890123456789012345678901234567890123456789");
|
||
#endif
|
||
|
||
|
||
//attaching an IRQ to CPUwritesToVideoPortPin
|
||
attachInterrupt(1, videoCharInterrupt, RISING);
|
||
digitalWrite(VideoBIT7pin, LOW); //default state after restart = 0 (ready to print)
|
||
}
|
||
|
||
void loop() {
|
||
//intentionally left blank
|
||
}
|
||
|
||
|
||
//interruption service routine (ISR)
|
||
void videoCharInterrupt(void) {
|
||
digitalWrite(VideoBIT7pin, HIGH);
|
||
|
||
scan_code = 0;
|
||
for (int count = 1; count <= 8 ; count++) {
|
||
int pinValue = digitalRead(DataBus[count-1]);
|
||
scan_code |= pinValue << (count-1);
|
||
};
|
||
scan_code = scan_code & 0x7F; //clear bit 7
|
||
|
||
if (scan_code == 0x7F)
|
||
{
|
||
digitalWrite(VideoBIT7pin, LOW);
|
||
return; //skip initial setup value
|
||
}
|
||
|
||
if (scan_code == 0xD)
|
||
{
|
||
tft.print('\n');
|
||
#ifdef _TERMINAL_
|
||
term.printLine("");
|
||
#endif
|
||
}
|
||
else
|
||
{
|
||
//make all symbols uppercase
|
||
if (scan_code >= 0x60)
|
||
scan_code -= 0x20;
|
||
|
||
//print only visible chars, starting from blanc
|
||
if (scan_code >= 0x20)
|
||
{
|
||
tft.print((char)scan_code);
|
||
#ifdef _TERMINAL_
|
||
term.send(scan_code);
|
||
#endif
|
||
}
|
||
//backspace
|
||
if (scan_code == 0x8)
|
||
{
|
||
//TV.print((char)scan_code);
|
||
}
|
||
|
||
}
|
||
digitalWrite(VideoBIT7pin, LOW);
|
||
}
|