diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index ec72a60..7d4ba9e 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -8,7 +8,7 @@ ], "defines": [], "compilerPath": "/usr/bin/avr-gcc", - "cStandard": "gnu17", + "cStandard": "gnu11", "cppStandard": "gnu++14", "intelliSenseMode": "gcc-avr", "configurationProvider": "ms-vscode.makefile-tools", diff --git a/build.d b/build.d index 7826bed..be2efd1 100755 --- a/build.d +++ b/build.d @@ -22,30 +22,66 @@ const string BUILD_DIR = "bin"; const string[] COMPILER_FLAGS = [ "-Wall", - "-Os" + "-Os", + "-g", + "-DF_CPU=16000000UL", + "-mmcu=atmega328p" ]; -int main(string[] args) { - if (args.length < 2) { - return build(); - } - string command = args[1].strip.toLower; - if (command == "flash") { - build().quitIfNonZero(); - return flashToMCU(buildPath("bin", "gympal.hex")); - } - if (command == "build") return build(true); - if (command == "clean") return clean(); +alias BuildCommand = int function(string[]); - writefln!"Unknown command: \"%s\"."(command); +int main(string[] args) { + string command; + if (args.length < 2) { + command = "help"; + } else { + command = args[1].strip.toLower; + } + + BuildCommand[string] commandMap = [ + "build": &buildCommand, + "flash": &flashCommand, + "clean": &clean, + "help": &helpCommand + ]; + + if (command !in commandMap) { + command = "help"; + } + + BuildCommand func = commandMap[command]; + string[] commandArgs = []; + if (args.length > 2) commandArgs = args[2 .. $]; + return func(commandArgs); +} + +int helpCommand(string[] args) { + writeln("build.d - A simple build script for C files."); + writeln("The following commands are available:"); + writeln("build [-f] - Compiles source code. Use -f to force rebuild."); + writeln(" By default, sources are hashed, and only built if changes are detected."); + writeln("flash [buildArgs] - Flashes code onto a connected AVR device via AVRDude."); + writeln("clean - Removes all build files."); + writeln("help - Shows this help information."); return 0; } -int clean() { +int clean(string[] args) { rmdirRecurse(BUILD_DIR); return 0; } +int buildCommand(string[] args) { + import std.algorithm : canFind; + return build(canFind(args, "-f")); +} + +int flashCommand(string[] args) { + int result = buildCommand(args); + if (result != 0) return result; + return flashToMCU(buildPath("bin", "gympal.hex")); +} + int build(bool force = false) { if (!exists(BUILD_DIR)) mkdir(BUILD_DIR); string[] sources = findFiles(SOURCE_DIR, ".c"); @@ -104,10 +140,8 @@ string compileSourceToObject(string sourcePath, bool force = false) { return objectPath; } - string cmd = format!"avr-gcc %s -DF_CPU=%dUL -mmcu=%s -c -o %s %s"( + string cmd = format!"avr-gcc %s -c -o %s %s"( flags, - CPU_FREQ, - MCU_ID, objectPath, sourcePath ); @@ -138,7 +172,7 @@ string linkObjects(string[] objectPaths) { string copyToHex(string elfFile) { string hexFile = buildPath(BUILD_DIR, "gympal.hex"); - string cmd = format!"avr-objcopy -O ihex -R .eeprom %s %s"( + string cmd = format!"avr-objcopy -j .data -j .text -O ihex %s %s"( elfFile, hexFile ); @@ -148,9 +182,8 @@ string copyToHex(string elfFile) { } int flashToMCU(string hexFile) { - string cmd = format!"avrdude -c %s -p %s -P /dev/ttyUSB0 -b %d flash:w:%s:i"( + string cmd = format!"avrdude -c %s -p m328p -P /dev/ttyUSB0 -b %d -u -U flash:w:%s:i"( BOOTLOADER, - MCU_ID, AVRDUDE_BAUDRATE, hexFile ); diff --git a/src/control.c b/src/control.c index 0a829fd..4e777fb 100644 --- a/src/control.c +++ b/src/control.c @@ -29,8 +29,7 @@ void ctl_init() { (1 << CTL_ROTARY_ENCODER_DT) | (1 << CTL_ROTARY_ENCODER_CLK) | (1 << CTL_BUTTON_A) | - (1 << CTL_BUTTON_B) | - (1 << CTL_BUTTON_C) + (1 << CTL_BUTTON_B) ); // Set up interrupts for handling control pin state changes. // Luckily, all interrupts happen on PCINT[16..23] so we only need one interrupt to handle them all. @@ -39,8 +38,7 @@ void ctl_init() { (1 << CTL_ROTARY_ENCODER_DT_INT) | (1 << CTL_ROTARY_ENCODER_CLK_INT) | (1 << CTL_BUTTON_A_INT) | - (1 << CTL_BUTTON_B_INT) | - (1 << CTL_BUTTON_C_INT) + (1 << CTL_BUTTON_B_INT) ); // Enable the global interrupt flag. sei(); diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..dade3dd --- /dev/null +++ b/src/display.c @@ -0,0 +1,18 @@ +#include "display.h" + +struct st7735 lcd; + +void display_init() { + ST7735_Init (&display_lcd); + ST7735_CommandSend (&display_lcd, MADCTL); + ST7735_Data8BitsSend (&display_lcd, 0x00); + ST7735_ClearScreen (&display_lcd, BLACK); + ST7735_SetPosition (5, 10); + ST7735_DrawString (&display_lcd, "Testing", WHITE, X1); +} + +void display_show_str(char* str) { + ST7735_ClearScreen(&display_lcd, BLACK); + ST7735_SetPosition(5, 10); + ST7735_DrawString(&display_lcd, str, WHITE, X1); +} \ No newline at end of file diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..5045832 --- /dev/null +++ b/src/display.h @@ -0,0 +1,27 @@ +#ifndef DISPLAY_H +#define DISPLAY_H + +#include "st7735.h" + +// A wrapper around the ST7735 library, which handles all of the gympal-specific display code. + +// Internal IO definition needed by the st7735 library. +// Chip Select +struct signal cs = { .ddr = &DDRB, .port = &PORTB, .pin = 2 }; +// Back Light +struct signal bl = { .ddr = &DDRB, .port = &PORTB, .pin = 1 }; +// Data / Command +struct signal dc = { .ddr = &DDRB, .port = &PORTB, .pin = 0 }; +// Reset +struct signal rs = { .ddr = &DDRD, .port = &PORTD, .pin = 7 }; +// LCD struct +struct st7735 display_lcd = { .cs = &cs, .bl = &bl, .dc = &dc, .rs = &rs }; + +/** + * @brief Initializes the display. + */ +void display_init(); + +void display_show_str(char* str); + +#endif \ No newline at end of file diff --git a/src/font.c b/src/font.c new file mode 100644 index 0000000..90491df --- /dev/null +++ b/src/font.c @@ -0,0 +1,117 @@ +/** + * ---------------------------------------------------------------+ + * @desc FONTs + * ---------------------------------------------------------------+ + * Copyright (C) 2020 Marian Hrinko. + * Written by Marian Hrinko (mato.hrinko@gmail.com) + * + * @author Marian Hrinko + * @datum 07.10.2020 + * @file font.c + * @tested AVR Atmega16 + * + * @depend + * ---------------------------------------------------------------+ + */ +#include "font.h" + +/** @array Charset */ +const uint8_t FONTS[][5] PROGMEM = { + { 0x00, 0x00, 0x00, 0x00, 0x00 }, // 20 space + { 0x81, 0x81, 0x18, 0x81, 0x81 }, // 21 ! +// { 0x00, 0x00, 0x5f, 0x00, 0x00 }, // 21 ! + { 0x00, 0x07, 0x00, 0x07, 0x00 }, // 22 " + { 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // 23 # + { 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // 24 $ + { 0x23, 0x13, 0x08, 0x64, 0x62 }, // 25 % + { 0x36, 0x49, 0x55, 0x22, 0x50 }, // 26 & + { 0x00, 0x05, 0x03, 0x00, 0x00 }, // 27 ' + { 0x00, 0x1c, 0x22, 0x41, 0x00 }, // 28 ( + { 0x00, 0x41, 0x22, 0x1c, 0x00 }, // 29 ) + { 0x14, 0x08, 0x3e, 0x08, 0x14 }, // 2a * + { 0x08, 0x08, 0x3e, 0x08, 0x08 }, // 2b + + { 0x00, 0x50, 0x30, 0x00, 0x00 }, // 2c , + { 0x08, 0x08, 0x08, 0x08, 0x08 }, // 2d - + { 0x00, 0x60, 0x60, 0x00, 0x00 }, // 2e . + { 0x20, 0x10, 0x08, 0x04, 0x02 }, // 2f / + { 0x3e, 0x51, 0x49, 0x45, 0x3e }, // 30 0 + { 0x00, 0x42, 0x7f, 0x40, 0x00 }, // 31 1 + { 0x42, 0x61, 0x51, 0x49, 0x46 }, // 32 2 + { 0x21, 0x41, 0x45, 0x4b, 0x31 }, // 33 3 + { 0x18, 0x14, 0x12, 0x7f, 0x10 }, // 34 4 + { 0x27, 0x45, 0x45, 0x45, 0x39 }, // 35 5 + { 0x3c, 0x4a, 0x49, 0x49, 0x30 }, // 36 6 + { 0x01, 0x71, 0x09, 0x05, 0x03 }, // 37 7 + { 0x36, 0x49, 0x49, 0x49, 0x36 }, // 38 8 + { 0x06, 0x49, 0x49, 0x29, 0x1e }, // 39 9 + { 0x00, 0x36, 0x36, 0x00, 0x00 }, // 3a : + { 0x00, 0x56, 0x36, 0x00, 0x00 }, // 3b ; + { 0x08, 0x14, 0x22, 0x41, 0x00 }, // 3c < + { 0x14, 0x14, 0x14, 0x14, 0x14 }, // 3d = + { 0x00, 0x41, 0x22, 0x14, 0x08 }, // 3e > + { 0x02, 0x01, 0x51, 0x09, 0x06 }, // 3f ? + { 0x32, 0x49, 0x79, 0x41, 0x3e }, // 40 @ + { 0x7e, 0x11, 0x11, 0x11, 0x7e }, // 41 A + { 0x7f, 0x49, 0x49, 0x49, 0x36 }, // 42 B + { 0x3e, 0x41, 0x41, 0x41, 0x22 }, // 43 C + { 0x7f, 0x41, 0x41, 0x22, 0x1c }, // 44 D + { 0x7f, 0x49, 0x49, 0x49, 0x41 }, // 45 E + { 0x7f, 0x09, 0x09, 0x09, 0x01 }, // 46 F + { 0x3e, 0x41, 0x49, 0x49, 0x7a }, // 47 G + { 0x7f, 0x08, 0x08, 0x08, 0x7f }, // 48 H + { 0x00, 0x41, 0x7f, 0x41, 0x00 }, // 49 I + { 0x20, 0x40, 0x41, 0x3f, 0x01 }, // 4a J + { 0x7f, 0x08, 0x14, 0x22, 0x41 }, // 4b K + { 0x7f, 0x40, 0x40, 0x40, 0x40 }, // 4c L + { 0x7f, 0x02, 0x0c, 0x02, 0x7f }, // 4d M + { 0x7f, 0x04, 0x08, 0x10, 0x7f }, // 4e N + { 0x3e, 0x41, 0x41, 0x41, 0x3e }, // 4f O + { 0x7f, 0x09, 0x09, 0x09, 0x06 }, // 50 P + { 0x3e, 0x41, 0x51, 0x21, 0x5e }, // 51 Q + { 0x7f, 0x09, 0x19, 0x29, 0x46 }, // 52 R + { 0x46, 0x49, 0x49, 0x49, 0x31 }, // 53 S + { 0x01, 0x01, 0x7f, 0x01, 0x01 }, // 54 T + { 0x3f, 0x40, 0x40, 0x40, 0x3f }, // 55 U + { 0x1f, 0x20, 0x40, 0x20, 0x1f }, // 56 V + { 0x3f, 0x40, 0x38, 0x40, 0x3f }, // 57 W + { 0x63, 0x14, 0x08, 0x14, 0x63 }, // 58 X + { 0x07, 0x08, 0x70, 0x08, 0x07 }, // 59 Y + { 0x61, 0x51, 0x49, 0x45, 0x43 }, // 5a Z + { 0x00, 0x7f, 0x41, 0x41, 0x00 }, // 5b [ + { 0x02, 0x04, 0x08, 0x10, 0x20 }, // 5c backslash + { 0x00, 0x41, 0x41, 0x7f, 0x00 }, // 5d ] + { 0x04, 0x02, 0x01, 0x02, 0x04 }, // 5e ^ + { 0x40, 0x40, 0x40, 0x40, 0x40 }, // 5f _ + { 0x00, 0x01, 0x02, 0x04, 0x00 }, // 60 ` + { 0x20, 0x54, 0x54, 0x54, 0x78 }, // 61 a + { 0x7f, 0x48, 0x44, 0x44, 0x38 }, // 62 b + { 0x38, 0x44, 0x44, 0x44, 0x20 }, // 63 c + { 0x38, 0x44, 0x44, 0x48, 0x7f }, // 64 d + { 0x38, 0x54, 0x54, 0x54, 0x18 }, // 65 e + { 0x08, 0x7e, 0x09, 0x01, 0x02 }, // 66 f + { 0x0c, 0x52, 0x52, 0x52, 0x3e }, // 67 g + { 0x7f, 0x08, 0x04, 0x04, 0x78 }, // 68 h + { 0x00, 0x44, 0x7d, 0x40, 0x00 }, // 69 i + { 0x20, 0x40, 0x44, 0x3d, 0x00 }, // 6a j + { 0x7f, 0x10, 0x28, 0x44, 0x00 }, // 6b k + { 0x00, 0x41, 0x7f, 0x40, 0x00 }, // 6c l + { 0x7c, 0x04, 0x18, 0x04, 0x78 }, // 6d m + { 0x7c, 0x08, 0x04, 0x04, 0x78 }, // 6e n + { 0x38, 0x44, 0x44, 0x44, 0x38 }, // 6f o + { 0x7c, 0x14, 0x14, 0x14, 0x08 }, // 70 p + { 0x08, 0x14, 0x14, 0x14, 0x7c }, // 71 q + { 0x7c, 0x08, 0x04, 0x04, 0x08 }, // 72 r + { 0x48, 0x54, 0x54, 0x54, 0x20 }, // 73 s + { 0x04, 0x3f, 0x44, 0x40, 0x20 }, // 74 t + { 0x3c, 0x40, 0x40, 0x20, 0x7c }, // 75 u + { 0x1c, 0x20, 0x40, 0x20, 0x1c }, // 76 v + { 0x3c, 0x40, 0x30, 0x40, 0x3c }, // 77 w + { 0x44, 0x28, 0x10, 0x28, 0x44 }, // 78 x + { 0x0c, 0x50, 0x50, 0x50, 0x3c }, // 79 y + { 0x44, 0x64, 0x54, 0x4c, 0x44 }, // 7a z + { 0x00, 0x08, 0x36, 0x41, 0x00 }, // 7b { + { 0x00, 0x00, 0x7f, 0x00, 0x00 }, // 7c | + { 0x00, 0x41, 0x36, 0x08, 0x00 }, // 7d } + { 0x10, 0x08, 0x08, 0x10, 0x08 }, // 7e ~ + { 0x00, 0x00, 0x00, 0x00, 0x00 } // 7f +}; diff --git a/src/font.h b/src/font.h new file mode 100644 index 0000000..0fec876 --- /dev/null +++ b/src/font.h @@ -0,0 +1,28 @@ +/** + * ---------------------------------------------------------------+ + * @desc FONTs + * ---------------------------------------------------------------+ + * Copyright (C) 2020 Marian Hrinko. + * Written by Marian Hrinko (mato.hrinko@gmail.com) + * + * @author Marian Hrinko + * @datum 07.10.2020 + * @file font.h + * @tested AVR Atmega16 + * + * @depend + * ---------------------------------------------------------------+ + */ +#include + +#ifndef __FONT_H__ +#define __FONT_H__ + + // Characters definition + // ----------------------------------- + // number of columns for chars + #define CHARS_COLS_LENGTH 5 + // @const Characters + extern const uint8_t FONTS[][CHARS_COLS_LENGTH]; + +#endif diff --git a/src/gympal.c b/src/gympal.c index 1cf8cd3..ceedfb4 100644 --- a/src/gympal.c +++ b/src/gympal.c @@ -2,23 +2,17 @@ #include #include "control.h" +#include "display.h" int main() { + display_init(); ctl_init(); - // Just for testing the interrupts, we're setting up B4 as an indicator LED. - DDRB |= 1 << PORTB4; - PORTB &= ~(1 << PORTB4); - uint8_t led = 0; - while(1) { - uint8_t v = ctl_isButtonAPressed(); - if (led != v) { - led = v; - if (led) { - PORTB |= 1 << PORTB4; - } else { - PORTB &= ~(1 << PORTB4); - } - } + while (1) { + if (ctl_isButtonAPressed()) { + display_show_str("button A"); + } else { + display_show_str("Not button A"); + } } return 0; } \ No newline at end of file diff --git a/src/st7735.c b/src/st7735.c new file mode 100644 index 0000000..7447967 --- /dev/null +++ b/src/st7735.c @@ -0,0 +1,817 @@ +/** + * --------------------------------------------------------------------------------------------+ + * @name ST773 1.8" LCD Driver + * --------------------------------------------------------------------------------------------+ + * Copyright (C) 2020 Marian Hrinko. + * Written by Marian Hrinko (mato.hrinko@gmail.com) + * + * @author Marian Hrinko + * @datum 13.10.2020 + * @update 01.07.2021 + * @file st7735.c + * @version 2.0 + * @tested AVR Atmega328 + * + * @depend font.h + * --------------------------------------------------------------------------------------------+ + * @descr Version 1.0 -> applicable for 1 display + * Version 2.0 -> applicable for more than 1 display + * --------------------------------------------------------------------------------------------+ + * @inspir http://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf + * https://github.com/adafruit/Adafruit-ST7735-Library + * http://w8bh.net/avr/AvrTFT.pdf + */ + +#include +#include +#include +#include "font.h" +#include "st7735.h" + +/** @array Init command */ +const uint8_t INIT_ST7735B[] PROGMEM = { + // number of initializers + 5, + // --------------------------------------- + // Software reset - no arguments, delay + 0, 150, SWRESET, + // Out of sleep mode, no arguments, delay + 0, 200, SLPOUT, + // Set color mode, 1 argument delay + 1, 10, COLMOD, 0x05, + // D7 D6 D5 D4 D3 D2 D1 D0 + // MY MX MV ML RGB MH - - + // ------------------------------ + // ------------------------------ + // MV MX MY -> {MV (row / column exchange) MX (column address order), MY (row address order)} + // ------------------------------ + // 0 0 0 -> begin left-up corner, end right-down corner + // left-right (normal view) + // 0 0 1 -> begin left-down corner, end right-up corner + // left-right (Y-mirror) + // 0 1 0 -> begin right-up corner, end left-down corner + // right-left (X-mirror) + // 0 1 1 -> begin right-down corner, end left-up corner + // right-left (X-mirror, Y-mirror) + // 1 0 0 -> begin left-up corner, end right-down corner + // up-down (X-Y exchange) + // 1 0 1 -> begin left-down corner, end right-up corner + // down-up (X-Y exchange, Y-mirror) + // 1 1 0 -> begin right-up corner, end left-down corner + // up-down (X-Y exchange, X-mirror) + // 1 1 1 -> begin right-down corner, end left-up corner + // down-up (X-Y exchange, X-mirror, Y-mirror) + // ------------------------------ + // ML: vertical refresh order + // 0 -> refresh top to bottom + // 1 -> refresh bottom to top + // ------------------------------ + // RGB: filter panel + // 0 -> RGB + // 1 -> BGR + // ------------------------------ + // MH: horizontal refresh order + // 0 -> refresh left to right + // 1 -> refresh right to left + // 0xA0 = 1010 0000 + 1, 0, MADCTL, 0xA0, + // Main screen turn on + 0, 200, DISPON + // --------------------------------------- +}; + +/** @var array Chache memory char index row */ +unsigned short int cacheMemIndexRow = 0; +/** @var array Chache memory char index column */ +unsigned short int cacheMemIndexCol = 0; + +/** + * @desc Hardware Reset + * + * @param struct signal * + * + * @return void + */ +void ST7735_Reset (struct signal * reset) +{ + // Actiavte pull-up resistor logical high on pin RST + // posible write: SET_BIT (*(*reset).port, reset->pin) + SET_BIT (*(reset->port), reset->pin); + // DDR as output + SET_BIT (*(reset->ddr), reset->pin); + // delay 200 ms + _delay_ms(200); + // Reset Low + CLR_BIT (*(reset->port), reset->pin); + // delay 200 ms + _delay_ms(200); + // Reset High + SET_BIT (*(reset->port), reset->pin); +} + +/** + * @desc Init SPI + * + * @param void + * + * @return void + */ +void ST7735_SPI_Init (void) +{ + // Output: SCK, MOSI + SET_BIT (DDR, ST7735_SCK); + SET_BIT (DDR, ST7735_MOSI); +/* + // Input: MISO with pullup + CLR_BIT (DDR, ST7735_MOSI); + PORT_BIT (PORT, ST7735_MOSI); +*/ + // SPE - SPI Enale + // MSTR - Master device + SET_BIT (SPCR, SPE); + SET_BIT (SPCR, MSTR); + // SPI2X - Prescaler fclk/2 = 8MHz + SET_BIT (SPSR, SPI2X); +} + +/** + * @desc Init Pins + * + * @param struct st7735 * + * + * @return void + */ +void ST7735_Pins_Init (struct st7735 * lcd) +{ + // DDR + // -------------------------------------- + SET_BIT (*(lcd->cs->ddr), lcd->cs->pin); + SET_BIT (*(lcd->bl->ddr), lcd->bl->pin); + SET_BIT (*(lcd->dc->ddr), lcd->dc->pin); + // PORT + // -------------------------------------- + SET_BIT (*(lcd->cs->port), lcd->cs->pin); // Chip Select H + SET_BIT (*(lcd->bl->port), lcd->bl->pin); // BackLigt ON +} + +/** + * @desc Init st7735 driver + * + * @param struct st7735 * + * + * @return void + */ +void ST7735_Init (struct st7735 * lcd) +{ + // init pins + ST7735_Pins_Init (lcd); + // init SPI + ST7735_SPI_Init (); + // hardware reset + ST7735_Reset (lcd->rs); + // load list of commands + ST7735_Commands (lcd, INIT_ST7735B); +} + +/** + * @desc Send list commands + * + * @param struct st7735 * + * @param const uint8_t * + * + * @return void + */ +void ST7735_Commands (struct st7735 * lcd, const uint8_t * initializers) +{ + uint8_t args; + uint8_t cmnd; + uint8_t time; + uint8_t loop = pgm_read_byte (initializers++); + + // loop through whole initializer list + while (loop--) { + + // 1st arg - number of command arguments + args = pgm_read_byte (initializers++); + // 2nd arg - delay time + time = pgm_read_byte (initializers++); + // 3th arg - command + cmnd = pgm_read_byte (initializers++); + + // send command + ST7735_CommandSend (lcd, cmnd); + // send arguments + while (args--) { + // send argument + ST7735_Data8BitsSend (lcd, pgm_read_byte (initializers++)); + } + // delay + ST7735_DelayMs (time); + } +} + +/** + * @desc Command send + * + * @param struct st7735 * + * @param uint8_t + * + * @return void + */ +uint8_t ST7735_CommandSend (struct st7735 * lcd, uint8_t data) +{ + // chip enable - active low + CLR_BIT (*(lcd->cs->port), lcd->cs->pin); + // command (active low) + CLR_BIT (*(lcd->dc->port), lcd->dc->pin); + // transmitting data + SPDR = data; + // wait till data transmit + WAIT_UNTIL_BIT_IS_SET (SPSR, SPIF); + // chip disable - idle high + SET_BIT (*(lcd->cs->port), lcd->cs->pin); + // return received data + return SPDR; +} + +/** + * @desc 8bits data send + * + * @param struct st7735 * + * @param uint8_t + * + * @return void + */ +uint8_t ST7735_Data8BitsSend (struct st7735 * lcd, uint8_t data) +{ + // chip enable - active low + CLR_BIT (*(lcd->cs->port), lcd->cs->pin); + // data (active high) + SET_BIT (*(lcd->dc->port), lcd->dc->pin); + // transmitting data + SPDR = data; + // wait till data transmit + WAIT_UNTIL_BIT_IS_SET (SPSR, SPIF); + // chip disable - idle high + SET_BIT (*(lcd->cs->port), lcd->cs->pin); + // return received data + return SPDR; +} + +/** + * @desc 16bits data send + * + * @param struct st7735 * lcd + * @param uint16_t + * + * @return void + */ +uint8_t ST7735_Data16BitsSend (struct st7735 * lcd, uint16_t data) +{ + // chip enable - active low + CLR_BIT (*(lcd->cs->port), lcd->cs->pin); + // data (active high) + SET_BIT (*(lcd->dc->port), lcd->dc->pin); + // transmitting data high byte + SPDR = (uint8_t) (data >> 8); + // wait till high byte transmit + WAIT_UNTIL_BIT_IS_SET (SPSR, SPIF); + // transmitting data low byte + SPDR = (uint8_t) (data); + // wait till low byte transmit + WAIT_UNTIL_BIT_IS_SET (SPSR, SPIF); + // chip disable - idle high + SET_BIT (*(lcd->cs->port), lcd->cs->pin); + // return received data + return SPDR; +} + +/** + * @desc Set window + * + * @param struct st7735 * lcd + * @param uint8_t x - start position + * @param uint8_t x - end position + * @param uint8_t y - start position + * @param uint8_t y - end position + * + * @return uint8_t + */ +uint8_t ST7735_SetWindow (struct st7735 * lcd, uint8_t x0, uint8_t x1, uint8_t y0, uint8_t y1) +{ + // check if coordinates is out of range + if ((x0 > x1) || + (x1 > SIZE_X) || + (y0 > y1) || + (y1 > SIZE_Y)) { + // out of range + return ST7735_ERROR; + } + // column address set + ST7735_CommandSend (lcd, CASET); + // send start x position + ST7735_Data16BitsSend (lcd, 0x0000 | x0); + // send end x position + ST7735_Data16BitsSend (lcd, 0x0000 | x1); + + // row address set + ST7735_CommandSend (lcd, RASET); + // send start y position + ST7735_Data16BitsSend (lcd, 0x0000 | y0); + // send end y position + ST7735_Data16BitsSend (lcd, 0x0000 | y1); + + // success + return ST7735_SUCCESS; +} + +/** + * @desc Write color pixels + * + * @param struct st7735 * lcd + * @param uint16_t color + * @param uint16_t counter + * + * @return void + */ +void ST7735_SendColor565 (struct st7735 * lcd, uint16_t color, uint16_t count) +{ + // access to RAM + ST7735_CommandSend (lcd, RAMWR); + // counter + while (count--) { + // write color + ST7735_Data16BitsSend (lcd, color); + } +} + +/** + * @desc Draw pixel + * + * @param struct st7735 * lcd + * @param uint8_t x position / 0 <= cols <= MAX_X-1 + * @param uint8_t y position / 0 <= rows <= MAX_Y-1 + * @param uint16_t color + * + * @return void + */ +void ST7735_DrawPixel (struct st7735 * lcd, uint8_t x, uint8_t y, uint16_t color) +{ + // set window + ST7735_SetWindow (lcd, x, x, y, y); + // draw pixel by 565 mode + ST7735_SendColor565 (lcd, color, 1); +} + +/** + * @desc RAM Content Show + * + * @param struct st7735 * lcd + * + * @return void + */ +void ST7735_RAM_Content_Show (struct st7735 * lcd) +{ + // display content on + ST7735_CommandSend (lcd, DISPON); +} + +/** + * @desc RAM Content Hide + * + * @param struct st7735 * lcd + * + * @return void + */ +void ST7735_RAM_Content_Hide (struct st7735 * lcd) +{ + // display content off + ST7735_CommandSend (lcd, DISPOFF); +} + +/** + * @desc Clear screen + * + * @param struct st7735 * + * @param uint16_t color + * + * @return void + */ +void ST7735_ClearScreen (struct st7735 * lcd, uint16_t color) +{ + // set whole window + ST7735_SetWindow (lcd, 0, SIZE_X, 0, SIZE_Y); + // draw individual pixels + ST7735_SendColor565 (lcd, color, CACHE_SIZE_MEM); +} + +/** + * @desc Draw character + * + * @param struct st7735 * + * @param char character + * @param uint16_t color + * @param enum Size (X1, X2, X3) + * + * @return void + */ +char ST7735_DrawChar (struct st7735 * lcd, char character, uint16_t color, enum Size size) +{ + // variables + uint8_t letter, idxCol, idxRow; + // check if character is out of range + if ((character < 0x20) && + (character > 0x7f)) { + // out of range + return 0; + } + // last column of character array - 5 columns + idxCol = CHARS_COLS_LEN; + // last row of character array - 8 rows / bits + idxRow = CHARS_ROWS_LEN; + + // -------------------------------------- + // SIZE X1 - normal font 1x high, 1x wide + // -------------------------------------- + if (size == X1) { + // loop through 5 bits + while (idxCol--) { + // read from ROM memory + letter = pgm_read_byte (&FONTS[character - 32][idxCol]); + // loop through 8 bits + while (idxRow--) { + // check if bit set + if (letter & (1 << idxRow)) { + // draw pixel + ST7735_DrawPixel (lcd, cacheMemIndexCol + idxCol, cacheMemIndexRow + idxRow, color); + } + } + // fill index row again + idxRow = CHARS_ROWS_LEN; + } + // update x position + cacheMemIndexCol = cacheMemIndexCol + CHARS_COLS_LEN + 1; + + // -------------------------------------- + // SIZE X2 - font 2x higher, normal wide + // -------------------------------------- + } else if (size == X2) { + // loop through 5 bytes + while (idxCol--) { + // read from ROM memory + letter = pgm_read_byte (&FONTS[character - 32][idxCol]); + // loop through 8 bits + while (idxRow--) { + // check if bit set + if (letter & (1 << idxRow)) { + // draw first left up pixel; + // (idxRow << 1) - 2x multiplied + ST7735_DrawPixel (lcd, cacheMemIndexCol + idxCol, cacheMemIndexRow + (idxRow << 1), color); + // draw second left down pixel + ST7735_DrawPixel (lcd, cacheMemIndexCol + idxCol, cacheMemIndexRow + (idxRow << 1) + 1, color); + } + } + // fill index row again + idxRow = CHARS_ROWS_LEN; + } + // update x position + cacheMemIndexCol = cacheMemIndexCol + CHARS_COLS_LEN + 1; + + // -------------------------------------- + // SIZE X3 - font 2x higher, 2x wider + // -------------------------------------- + } else if (size == X3) { + // loop through 5 bytes + while (idxCol--) { + // read from ROM memory + letter = pgm_read_byte (&FONTS[character - 32][idxCol]); + // loop through 8 bits + while (idxRow--) { + // check if bit set + if (letter & (1 << idxRow)) { + // draw first left up pixel; + // (idxRow << 1) - 2x multiplied + ST7735_DrawPixel (lcd, cacheMemIndexCol + (idxCol << 1), cacheMemIndexRow + (idxRow << 1), color); + // draw second left down pixel + ST7735_DrawPixel (lcd, cacheMemIndexCol + (idxCol << 1), cacheMemIndexRow + (idxRow << 1) + 1, color); + // draw third right up pixel + ST7735_DrawPixel (lcd, cacheMemIndexCol + (idxCol << 1) + 1, cacheMemIndexRow + (idxRow << 1), color); + // draw fourth right down pixel + ST7735_DrawPixel (lcd, cacheMemIndexCol + (idxCol << 1) + 1, cacheMemIndexRow + (idxRow << 1) + 1, color); + } + } + // fill index row again + idxRow = CHARS_ROWS_LEN; + } + + // update x position + cacheMemIndexCol = cacheMemIndexCol + CHARS_COLS_LEN + CHARS_COLS_LEN + 1; + } + + // return exit + return ST7735_SUCCESS; +} + +/** + * @desc Set text position x, y + * + * @param uint8_t x - position + * @param uint8_t y - position + * + * @return char + */ +char ST7735_SetPosition (uint8_t x, uint8_t y) +{ + // check if coordinates is out of range + if ((x > MAX_X) && (y > MAX_Y)) { + // error + return ST7735_ERROR; + + } else if ((x > MAX_X) && (y <= MAX_Y)) { + // set position y + cacheMemIndexRow = y; + // set position x + cacheMemIndexCol = 2; + } else { + // set position y + cacheMemIndexRow = y; + // set position x + cacheMemIndexCol = x; + } + // success + return ST7735_SUCCESS; +} + +/** + * @desc Check text position x, y + * + * @param unsigned char x - position + * @param unsigned char y - position + * @param unsigned char + * + * @return char + */ +char ST7735_CheckPosition (unsigned char x, unsigned char y, unsigned char max_y, enum Size size) +{ + // check if coordinates is out of range + if ((x > MAX_X) && (y > max_y)) { + // out of range + return ST7735_ERROR; + + } + // if next line + if ((x > MAX_X) && (y <= max_y)) { + // set position y + cacheMemIndexRow = y; + // set position x + cacheMemIndexCol = 2; + } + + // success + return ST7735_SUCCESS; +} + +/** + * @desc Draw string + * + * @param struct st7735 * + * @param char * string + * @param uint16_t color + * @param enum Size (X1, X2, X3) + * + * @return void + */ +void ST7735_DrawString (struct st7735 * lcd, char *str, uint16_t color, enum Size size) +{ + // variables + unsigned int i = 0; + unsigned char check; + unsigned char delta_y; + unsigned char max_y_pos; + unsigned char new_x_pos; + unsigned char new_y_pos; + + // loop through character of string + while (str[i] != '\0') { + // max x position character + new_x_pos = cacheMemIndexCol + CHARS_COLS_LEN + (size & 0x0F); + // delta y + delta_y = CHARS_ROWS_LEN + (size >> 4); + // max y position character + new_y_pos = cacheMemIndexRow + delta_y; + // max y pos + max_y_pos = MAX_Y - delta_y; + // control if will be in range + check = ST7735_CheckPosition (new_x_pos, new_y_pos, max_y_pos, size); + // update position + if (ST7735_SUCCESS == check) { + // read characters and increment index + ST7735_DrawChar (lcd, str[i++], color, size); + } + } +} + +/** + * @desc Draw line by Bresenham algoritm + * @surce https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm + * + * @param struct st7735 * + * @param uint8_t x start position / 0 <= cols <= MAX_X-1 + * @param uint8_t x end position / 0 <= cols <= MAX_X-1 + * @param uint8_t y start position / 0 <= rows <= MAX_Y-1 + * @param uint8_t y end position / 0 <= rows <= MAX_Y-1 + * @param uint16_t color + * + * @return void + */ +char ST7735_DrawLine (struct st7735 * lcd, uint8_t x1, uint8_t x2, uint8_t y1, uint8_t y2, uint16_t color) +{ + // determinant + int16_t D; + // deltas + int16_t delta_x, delta_y; + // steps + int16_t trace_x = 1, trace_y = 1; + + // delta x + delta_x = x2 - x1; + // delta y + delta_y = y2 - y1; + + // check if x2 > x1 + if (delta_x < 0) { + // negate delta x + delta_x = -delta_x; + // negate step x + trace_x = -trace_x; + } + + // check if y2 > y1 + if (delta_y < 0) { + // negate detla y + delta_y = -delta_y; + // negate step y + trace_y = -trace_y; + } + + // Bresenham condition for m < 1 (dy < dx) + if (delta_y < delta_x) { + // calculate determinant + D = (delta_y << 1) - delta_x; + // draw first pixel + ST7735_DrawPixel (lcd, x1, y1, color); + // check if x1 equal x2 + while (x1 != x2) { + // update x1 + x1 += trace_x; + // check if determinant is positive + if (D >= 0) { + // update y1 + y1 += trace_y; + // update determinant + D -= 2*delta_x; + } + // update deteminant + D += 2*delta_y; + // draw next pixel + ST7735_DrawPixel (lcd, x1, y1, color); + } + // for m > 1 (dy > dx) + } else { + // calculate determinant + D = delta_y - (delta_x << 1); + // draw first pixel + ST7735_DrawPixel (lcd, x1, y1, color); + // check if y2 equal y1 + while (y1 != y2) { + // update y1 + y1 += trace_y; + // check if determinant is positive + if (D <= 0) { + // update y1 + x1 += trace_x; + // update determinant + D += 2*delta_y; + } + // update deteminant + D -= 2*delta_x; + // draw next pixel + ST7735_DrawPixel (lcd, x1, y1, color); + } + } + // success return + return 1; +} + +/** + * @desc Fast draw line horizontal + * + * @param struct st7735 * + * @param uint8_t xs - start position + * @param uint8_t xe - end position + * @param uint8_t y - position + * @param uint16_t color + * + * @return void + */ +void ST7735_DrawLineHorizontal (struct st7735 * lcd, uint8_t xs, uint8_t xe, uint8_t y, uint16_t color) +{ + uint8_t temp; + // check if start is > as end + if (xs > xe) { + // temporary safe + temp = xs; + // start change for end + xe = xs; + // end change for start + xs = temp; + } + // set window + ST7735_SetWindow (lcd, xs, xe, y, y); + // draw pixel by 565 mode + ST7735_SendColor565 (lcd, color, xe - xs); +} + +/** + * @desc Fast draw line vertical + * + * @param struct st7735 * + * @param uint8_t x - position + * @param uint8_t ys - start position + * @param uint8_t ye - end position + * @param uint16_t color + * + * @return void + */ +void ST7735_DrawLineVertical (struct st7735 * lcd, uint8_t x, uint8_t ys, uint8_t ye, uint16_t color) +{ + uint8_t temp; + // check if start is > as end + if (ys > ye) { + // temporary safe + temp = ys; + // start change for end + ye = ys; + // end change for start + ys = temp; + } + // set window + ST7735_SetWindow (lcd, x, x, ys, ye); + // draw pixel by 565 mode + ST7735_SendColor565 (lcd, color, ye - ys); +} + +/** + * @desc Draw rectangle + * + * @param struct st7735 * + * @param uint8_t x start position + * @param uint8_t x end position + * @param uint8_t y start position + * @param uint8_t y end position + * @param uint16_t color + * + * @return void + */ +void ST7735_DrawRectangle (struct st7735 * lcd, uint8_t xs, uint8_t xe, uint8_t ys, uint8_t ye, uint16_t color) +{ + uint8_t temp; + // check if start is > as end + if (xs > xe) { + // temporary safe + temp = xe; + // start change for end + xe = xs; + // end change for start + xs = temp; + } + // check if start is > as end + if (ys > ye) { + // temporary safe + temp = ye; + // start change for end + ye = ys; + // end change for start + ys = temp; + } + // set window + ST7735_SetWindow (lcd, xs, xe, ys, ye); + // send color + ST7735_SendColor565 (lcd, color, (xe-xs+1)*(ye-ys+1)); +} + +/** + * @desc Delay + * + * @param uint8_t time in milliseconds / max 256ms + * + * @return void + */ +void ST7735_DelayMs (uint8_t time) +{ + // loop through real time + while (time--) { + // 1 s delay + _delay_ms(1); + } +} diff --git a/src/st7735.h b/src/st7735.h new file mode 100644 index 0000000..a99db1e --- /dev/null +++ b/src/st7735.h @@ -0,0 +1,423 @@ +/** + * --------------------------------------------------------------------------------------------+ + * @name ST773 1.8" LCD Driver + * --------------------------------------------------------------------------------------------+ + * Copyright (C) 2020 Marian Hrinko. + * Written by Marian Hrinko (mato.hrinko@gmail.com) + * + * @author Marian Hrinko + * @datum 13.10.2020 + * @update 01.07.2021 + * @file st7735.h + * @version 2.0 + * @tested AVR Atmega328 + * + * @depend font.h + * --------------------------------------------------------------------------------------------+ + * @descr Version 1.0 -> applicable for 1 display + * Version 2.0 -> applicable for more than 1 display + * --------------------------------------------------------------------------------------------+ + * @inspir http://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf + * https://github.com/adafruit/Adafruit-ST7735-Library + * http://w8bh.net/avr/AvrTFT.pdf + */ + +#include + +#ifndef __ST7735_H__ +#define __ST7735_H__ + + // Success / Error + // ----------------------------------- + #define ST7735_SUCCESS 0 + #define ST7735_ERROR 1 + + // PORT/PIN definition + // ----------------------------------- + #define PORT PORTB + #define DDR DDRB + #define ST7735_MOSI 3 // SDA + #define ST7735_MISO 4 + #define ST7735_SCK 5 // SCL + + // Command definition + // ----------------------------------- + #define DELAY 0x80 + + #define NOP 0x00 + #define SWRESET 0x01 + #define RDDID 0x04 + #define RDDST 0x09 + + #define SLPIN 0x10 + #define SLPOUT 0x11 + #define PTLON 0x12 + #define NORON 0x13 + + #define INVOFF 0x20 + #define INVON 0x21 + #define DISPOFF 0x28 + #define DISPON 0x29 + #define RAMRD 0x2E + #define CASET 0x2A + #define RASET 0x2B + #define RAMWR 0x2C + + #define PTLAR 0x30 + #define MADCTL 0x36 + #define COLMOD 0x3A + + #define FRMCTR1 0xB1 + #define FRMCTR2 0xB2 + #define FRMCTR3 0xB3 + #define INVCTR 0xB4 + #define DISSET5 0xB6 + + #define PWCTR1 0xC0 + #define PWCTR2 0xC1 + #define PWCTR3 0xC2 + #define PWCTR4 0xC3 + #define PWCTR5 0xC4 + #define VMCTR1 0xC5 + + #define RDID1 0xDA + #define RDID2 0xDB + #define RDID3 0xDC + #define RDID4 0xDD + + #define GMCTRP1 0xE0 + #define GMCTRN1 0xE1 + + #define PWCTR6 0xFC + + // Colors + // ----------------------------------- + #define BLACK 0x0000 + #define WHITE 0xFFFF + #define RED 0xF000 + #define GREEN 0x0F00 + #define BLUE 0x00F0 + + // AREA definition + // ----------------------------------- + #define MAX_X 161 // max columns / MV = 0 in MADCTL + #define MAX_Y 130 // max rows / MV = 0 in MADCTL + #define SIZE_X MAX_X - 1 // columns max counter + #define SIZE_Y MAX_Y - 1 // rows max counter + #define CACHE_SIZE_MEM (MAX_X * MAX_Y) // whole pixels + #define CHARS_COLS_LEN 5 // number of columns for chars + #define CHARS_ROWS_LEN 8 // number of rows for chars + + + // FUNCTION macros + // ----------------------------------- + // clear bit + #define CLR_BIT(port, bit) ( ((port) &= ~(1 << (bit))) ) + // set bit + #define SET_BIT(port, bit) ( ((port) |= (1 << (bit))) ) + // bit is clear? + #define IS_BIT_CLR(port, bit) ( IS_BIT_SET(port, bit) ? 0 : 1 ) + // bit is set? + #define IS_BIT_SET(port, bit) ( ((port) & (1 << (bit))) ? 1 : 0 ) + // wait until bit is set + #define WAIT_UNTIL_BIT_IS_SET(port, bit) { while (IS_BIT_CLR(port, bit)); } + + /** @const Command list ST7735B */ + extern const uint8_t INIT_ST7735B[]; + /** @var array Chache memory char index row */ + unsigned short int cacheMemIndexRow; + /** @var array Chache memory char index column */ + unsigned short int cacheMemIndexCol; + + /** @enum Font sizes */ + enum Size { + // 1x high & 1x wide size + X1 = 0x00, + // 2x high & 1x wide size + X2 = 0x80, + // 2x high & 2x wider size + // 0x0A is set because need to offset 5 position to right + // when draw the characters of string + X3 = 0x81 + }; + + /** @struct Signal */ + struct signal { + // ddr + volatile uint8_t * ddr; + // port + volatile uint8_t * port; + // pin + uint8_t pin; + }; + + /** @struct Lcd */ + struct st7735 { + // Chip Select + struct signal * cs; + // Back Light + struct signal * bl; + // Data / Command + struct signal * dc; + // Reset + struct signal * rs; + }; + + /** + * @desc Init st7735 driver + * + * @param struct st7735 * + * + * @return void + */ + void ST7735_Init (struct st7735 *); + + /** + * @desc Hardware Reset + * + * @param struct signal * + * + * @return void + */ + void ST7735_Reset (struct signal *); + + /** + * @desc Init SPI + * + * @param void + * + * @return void + */ + void ST7735_SPI_Init (void); + + /** + * @desc Init PINS + * + * @param struct st7735 * + * + * @return void + */ + void ST7735_Pins_Init (struct st7735 *); + + /** + * @desc Send list commands + * + * @param struct st7735 * + * @param const uint8_t * + * + * @return void + */ + void ST7735_Commands (struct st7735 *, const uint8_t *commands); + + /** + * @desc Command send + * + * @param struct st7735 * + * @param uint8_t + * + * @return uint8_t + */ + uint8_t ST7735_CommandSend (struct st7735 *, uint8_t); + + /** + * @desc 8bits data send + * + * @param struct st7735 * + * @param uint8_t + * + * @return uint8_t + */ + uint8_t ST7735_Data8BitsSend (struct st7735 *, uint8_t); + + /** + * @desc 16bits data send + * + * @param struct st7735 * + * @param uint16_t + * + * @return uint8_t + */ + uint8_t ST7735_Data16BitsSend (struct st7735 *, uint16_t); + + /** + * @desc Set window + * + * @param struct st7735 * + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint8_t + * + * @return uint8_t + */ + uint8_t ST7735_SetWindow (struct st7735 *, uint8_t, uint8_t, uint8_t, uint8_t); + + /** + * @desc Write color pixels + * + * @param struct st7735 * + * @param uint16_t + * @param uint16_t + * + * @return void + */ + void ST7735_SendColor565 (struct st7735 *, uint16_t, uint16_t); + + /** + * @desc Draw pixel + * + * @param struct st7735 * + * @param uint8_t + * @param uint8_t + * @param uint16_t + * + * @return void + */ + void ST7735_DrawPixel (struct st7735 *, uint8_t, uint8_t, uint16_t); + + /** + * @desc Clear screen + * + * @param struct st7735 * + * @param uint16_t + * + * @return void + */ + void ST7735_ClearScreen (struct st7735 *, uint16_t); + + /** + * @desc RAM Content Show + * + * @param struct st7735 * + * + * @return void + */ + void ST7735_RAM_Content_Show (struct st7735 *); + + /** + * @desc RAM Content Hide + * + * @param struct st7735 * + * + * @return void + */ + void ST7735_RAM_Content_Hide (struct st7735 *); + + /** + * @desc Display ON + * + * @param struct st7735 * lcd + * + * @return void + */ + void ST7735_DisplayOn (struct st7735 *); + + /** + * @desc Check text position x, y + * + * @param unsigned char + * @param unsigned char + * @param unsigned char + * + * @return char + */ + char ST7735_CheckPosition (unsigned char, unsigned char, unsigned char, enum Size); + + /** + * @desc Set text position x, y + * + * @param uint8_t + * @param uint8_t + * + * @return char + */ + char ST7735_SetPosition (uint8_t, uint8_t); + + /** + * @desc Draw character + * + * @param struct st7735 * + * @param char + * @param uint16_t + * @param enum Size (X1, X2, X3) + * + * @return void + */ + char ST7735_DrawChar (struct st7735 *, char, uint16_t, enum Size); + + /** + * @desc Draw string + * + * @param struct st7735 * + * @param char * + * @param uint16_t + * @param enum Size (X1, X2, X3) + + * @return void + */ + void ST7735_DrawString (struct st7735 *, char *, uint16_t, enum Size); + + /** + * @desc Draw line + * + * @param struct st7735 * + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint16_t + * + * @return void + */ + char ST7735_DrawLine (struct st7735 *, uint8_t, uint8_t, uint8_t, uint8_t, uint16_t); + + /** + * @desc Fast draw line horizontal + * + * @param struct st7735 * + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint16_t + * + * @return void + */ + void ST7735_DrawLineHorizontal (struct st7735 *, uint8_t, uint8_t, uint8_t, uint16_t); + + /** + * @desc Fast draw line vertical + * + * @param struct st7735 * + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint16_t + * + * @return void + */ + void ST7735_DrawLineVertical (struct st7735 *, uint8_t, uint8_t, uint8_t, uint16_t); + + /** + * @desc Draw rectangle + * + * @param struct st7735 * + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint8_t + * @param uint16_t + * + * @return void + */ + void ST7735_DrawRectangle (struct st7735 *, uint8_t, uint8_t, uint8_t, uint8_t, uint16_t); + + /** + * @desc Delay + * + * @param uint8_t + * + * @return void + */ + void ST7735_DelayMs (uint8_t); + +#endif