Added LCD library and preparing to start work on OS.

This commit is contained in:
Andrew Lalis 2023-01-03 19:40:20 +01:00
parent 4dfad70e9b
commit d041658da9
10 changed files with 1494 additions and 39 deletions

View File

@ -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",

73
build.d
View File

@ -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
);

View File

@ -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();

18
src/display.c Normal file
View File

@ -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);
}

27
src/display.h Normal file
View File

@ -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

117
src/font.c Normal file
View File

@ -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
};

28
src/font.h Normal file
View File

@ -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 <avr/pgmspace.h>
#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

View File

@ -2,23 +2,17 @@
#include <util/delay.h>
#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;
}

817
src/st7735.c Normal file
View File

@ -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 <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#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);
}
}

423
src/st7735.h Normal file
View File

@ -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 <avr/pgmspace.h>
#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