Saturday, February 5, 2022

Library for ST7735 TFT display driver for AVR microcontrollers

There are already some libraries for the ST7735 display driver such as the one from Adafruit but made only for Arduino. I needed one for AVR microcontrollers in general, so I made this one. With a bit of twiking it could also be adapted to work with other types of microcontrollers. This library is based on the one from Adafruit but with some functions removed, modified and others added. The interface needs 4 microcontroller pins and it uses SPI for communication.

Library for the ST7735 TFT display driver for AVR microcontrollers

Library for the ST7735 TFT display driver for AVR microcontrollers demo

There are many GUI elements that can be created and above are a few examples such as: selectable menus, scrollbars, check-boxes and animated icons. I made those in Inkscape for a battery charger project.

Contents:


Wiring the ST7735 TFT display

It is important to note that the power supply voltage for the ST7735 display driver is maximum 3.3V and same for the other input pins. Some TFT modules include a 3.3V regulator and a voltage level shifter in which case it can be used with 5V microcontrollers, if not some level shifting must be done if the microcontroller is not powered from 3.3V.

ST7735 connection diagram with voltage level shifter

This schematic is an example that also includes an SD card. Here, MISO is used for DC pin (Data/Command) since the ST7735 doesn't use the MISO in the 1-Wire SPI protocol, and also as MISO (Master In Slave Out) for the SD card. The 74AHC125D can't be used for this pin since is not bi-directional, hence the mosfet level shifter.

ST7735 connection diagram with voltage level shifters and pinout

1 - GND - ground power supply

2 - VCC - 3.3V power supply (minimum 150mA)

3 - SCL - SPI serial clock pin (SCK)

4 - SDA - SPI serial data input/output (MOSI)

This pin is mostly used as an input pin - the microcontroller sends data to the display driver - but is also used as an output - the display driver sends data out to the microcontroller. This is needed to identify the display by reading the manufacturer ID, version ID and driver ID. A voltage level shifter IC such as 74AHC125 can not be used here because is not bi-directional. For this purpose a cheap level shifter using one N-channel signal mosfet and two resistors can be used. Here is a link that describes how this bi-directional voltage level shifter works.

5 - RES - this pin is reset input signal. When the pin is low, initialization of the chip is executed. Keep this pin pull high during normal operation.

The initialization function is using a software reset command and I have noticed that the display works without the hardware reset pin so I don't know in what scenarios could be needed. If you have pins to spare connect this to a microcontroller pin, if not connect it to 3.3V.

Update: connecting the RESET pin to 3.3V is unreliable - sometimes the display gets initialized but most of the times not. Other than using a microcontroller pin, a solution would be to use a 10k pull-up resistor from Reset to 3.3V, then a small signal diode with the anode (+) connected to the Reset pin and cathode (-) connected to the Reset pin of the microcontroller. The diode is needed to protect the display when the microcontroller is powered from 5V. I am using this method in my custom development board project with good results.

6 - D/C - Data/Command control. Depending on the state of the pin (high or low) this informs the LCD driver whether the data is a command or data. Can be connected to any pin of the microcontroller.

7 - CS - Chip Select. Can be SPI SS pin or any other pin.

8 - BL - Backlight control pin. This pin is tied to the base of a NPN transistor and it can be connected to 3.3V to have the backlight always on or to a microcontroller pin for more control.

Voltage level shifting

To interface a 5V microcontroller with the ST7735 3.3V driver, a buffer such as 74AHC125 can be used as a voltage level shifter. The 5V input goes to the A pins and the 3.3V outputs goes from the Y pins to the display driver. The OE (Output Enable) pins must be tied to ground to activate the output for each pin pair. The 74AHC125chip must be powered from the 3.3V supply.

The SS pin

It is important that the SS pin of the microcontroller is set as an output - low or high - otherwise the SPI won't work properly. This is related to how the AVR SPI works. Consult the AVR datasheet for your device to find  the port and pin number of the SS pin.

The MISO pin

The ST7735 is not a true SPI device. It's using MOSI and SCK but not MISO because MOSI is also used for sending data from the display driver to the microcontroller. Then you might think "Great, I could use MISO for something else!". Yes, but not really. That is because while the SPI is enabled the MISO pin is set to input mode and can't be changed. You could use it to read a button for example but since the display needs a pin for D/C (Data/Command) you might as well use it for this purpose.

To be able to set the MISO pin high or low I have mixed hardware SPI with software SPI. When D/C pin must be set low, the hardware SPI is disabled and soft SPI is used. When SPI is enabled the MISO pin is always high. The drawback of using soft SPI is the lower speed - 8MHz vs 0.8MHz but on the display is barely noticeable.

To enable soft SPI set the following constant to 1. To always use hardware SPI set it to 0:

#define MISO_FOR_DC	1


ST7735 library

Initialization function and types of ST7735 modules

DIS_ST7735_displayInit()

This function sets the pins, the SPI and sends some commands to the LCD driver for initialization.

The thing is that there are many types of ST7735 display modules and the type of commands needed for initialization can vary depending on the module. The Adafruit library is using the tab color that the display comes with, but what if the sticker is removed and you don't know what color it was? Apart from that other sources say that this is not a reliable method of identification regardless. I think the best method would be to use the manufacturer ID, version ID and driver ID by reading them from the display chip. But since I only have one display I don't know how to correlate this data to the necessary commands.

So if your display doesn't work with the actual commands let me know in the comments and I will give some suggestions with some new settings and if it works you can post the manufacturer ID, version ID and driver ID in the comments and this way other users with the same display can benefit.

The functions for reading the data are:

DIS_ST7735_readManufacturerID()

DIS_ST7735_readVersionID()

DIS_ST7735_readDriverID()

 

The Colors

Many functions take a color as an argument so it is good to talk a bit about the colors. The display uses 16-bits 5-6-5 RGB format so regular RGB colors won't work. There are some colors included with the library such as ST77XX_BLACK, ST77XX_WHITE, ST77XX_RED, ST77XX_GREEN, etc. and more can be added. First pick a color; this site can be used for example https://htmlcolorcodes.com/color-names, and then convert it to the 565 RGB format using this app https://github.com/lgaland/rgb-converter or this online tool http://greekgeeks.net/#maker-tools_convertColor.

Update: I have added a function that can be used to convert between regular RGB to 16-bits 5-6-5 RGB.

This function converts a 24-bits 8-8-8 RGB color into a 16-bits color. The returned value can be used as an argument to any function that requires a 16-bit color.

uint16_t rgbConvert24to16()

Parameters:

uint32_t rgb24

a 32-bit RGB color

Usage:

uint16_t color = rgbConvert24to16(0xFF0000);
DIS_ST7735_setFontColor(color);
DIS_ST7735_drawString("Hello world!");
 

The Cursor and the Coordinate System

Each pixel on the display is addressed by it's horizontal (X) and vertical (Y) coordinate. The origin of the coordinate system is at the top left corner with positive X increasing to the right and positive Y increasing downward.

ST7735 TFT display coordinate system

Because the first pixel starts from 0 the last pixel is the display width or height minus 1.

Clearing the display

 
DIS_ST7735_fillScreen(uint16_t color)

Fills the screen completely with one color. Can also be used to clear the entire screen. Must be used after the init function otherwise the screen will start with random colored pixels.

Usage:

DIS_ST7735_fillScreen(ST77XX_BLACK)

A better way to update the display is to clear only the parts that have changed. Clearing the entire display only to update a number somewhere will create a noticeable flicker. To update a text or number use the DIS_ST7735_fillRect() function to erase that part of the screen with the background color then print new data in place. A code example can be found at the end.

Another way of clearing the display with less flicker is by using the following function.

DIS_ST7735_setBackgroundColor()
 
Parameters 
 
uint16_t background_color
 

This function uses the background_color before drawing text or numbers to erase previous character. Because it erases only a character then prints another in place the result has less flicker that erasing an entire line. It still has some unavoidable flicker but is more like twinkling stars than a vertical scanning line. The disadvantage over the fillRect() method is that the text/number must be the same length or greater than the previous one. To disable the function pass 1 instead of a color.


Text Functions

Setting the font family

 
DIS_ST7735_setFont(const GFXfont *f)

Adafruit provides some fonts with different sizes that can be downloaded from https://github.com/adafruit/Adafruit-GFX-Library.

"Each filename starts with the face name (“FreeMono”, “FreeSerif”, etc.) followed by the style (“Bold”, “Oblique”, none, etc.), font size in points (currently 9, 12, 18 and 24 point sizes are provided) and “7b” to indicate that these contain 7-bit characters (ASCII codes “ ” through “~”); 8-bit fonts (supporting symbols and/or international characters) are not yet provided but may come later."

More about the fonts can be found on Adafruit's website: https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts.

To see which one you like first include the font. For example:

#include "Fonts/arial6pt7b.h"

The larger the font size the more space will occupy. You could include more than one font but that will use lots of flash space on the microcontroller.

Next pass the address of the structure to the setFont function:

DIS_ST7735_setFont(&arial6pt7b)

The name of the data structure is the same as the included filename font without the .h 

Making the font bold

 
void DIS_ST7735_setFontBold()

Normally if you want to use normal and bold text you have to include two separate fonts which would increase the code size considerably. This is a cheap way to bold the text on-the-fly with only one line of code.

Parameters


bool bold

pass true to make the font bold or false to use the normal font

ST7735 TFT bold text

Usage:

DIS_ST7735_drawString("Hello world!");
DIS_ST7735_gotoNextLine(0);
DIS_ST7735_setFontBold(true);
DIS_ST7735_drawString("Hello world!");
 

Creating your own custom fonts

Suppose you have a favorite .ttf or .otf font and want to use it. The Adafruit has a very good tutorial for that here https://github.com/adafruit/Adafruit-GFX-Library/blob/master/fontconvert/fontconvert_win.md, and although there are quite a few steps to follow, the actual font generation only require one command line, the rest are only needed to generate the "fontconvert.exe". Since I already have compiled the file, it will be included at the end of this article if you need it. Then place the .ttf font and fontconvert.exe inside the fontconvert folder. On Windows press CTRL+L then type cmd to open a command prompt window with the fondconvert folder path.

As a test example I used the Barchella_Drumal.otf font that can be downloaded for free at this link https://www.dafont.com/barchella-drumal.font. To generate the header file run this command:

fontconvert.exe Barchella_Drumal.otf 9 > Barchella_Drumal9pt7b.h

9 is the font size and can be experimented with.


Displaying text


uint8_t DIS_ST7735_drawString()
 

Parameters

 
const char *c

a string of text

Draws a string of characters starting from the current cursor location. The cursor will be incremented automatically after each character. When the cursor reaches the end of the screen, the function will return 1. The normal return value is 0. This is to assure than the information is not lost or overwritten when the screen is full. To unlock the function simply set the cursor to the top or other position when the function returns 1.

To find how many characters were printed before the overflow condition occurred use the return value of:

uint16_t DIS_ST7735_getStringOffset(void)

This value can be used to offset the string pointer. Example:

uint8_t return_code;
uint16_t idx = 0;
uint8_t StringBuffer[512];

return_code = DIS_ST7735_drawString((char*)StringBuffer);

while(return_code){
	return_code = DIS_ST7735_drawString((char*)&StringBuffer[idx]);
			
	_delay_ms(5000);
	DIS_ST7735_setCursor(5, DIS_ST7735_getLineHeight());
	DIS_ST7735_fillScreen(ST77XX_WHITE);
	idx += DIS_ST7735_getStringOffset();
}

Since the library doesn't support Unicode, all Unicode characters will be replaced with the '_' character.

The characters are printed from the Y cursor up so the height of the text must be considered when setting the cursor on Y position by using the getLineHeight() function for the first line.

DIS_ST7735_setCursor(5, DIS_ST7735_getLineHeight());
DIS_ST7735_drawString("Hello world!");

In the above example the text will be printed starting 5px from left and at the top of the screen. To print on the next line with 5px left margin, use:

DIS_ST7735_gotoNextLine(5)

All the text related functions such as setFontSize() or setFontBold() must be used before printing the text.

Display a single character

 
DIS_ST7735_drawChar(x, y, character)

Draw a single character at the (x, y) coordinate.

Usage:

DIS_ST7735_drawChar(5, 5, 'V')

Set the font size

 
DIS_ST7735_setFontSize() 
 

Parameters 


size_x, size_y

Size x is the width and size y is the height of the font. By default the text size is set to 1, 1. Because the fonts are bitmaps and not scalable vectors and the algorithm used is very simple as to not increase the code size too much, the resulted sized text will be a bit blocky. If you like Minecraft it might be ok if not you could use a larger font to begin with.

Set the font color


DIS_ST7735_setFontColor()
 

Parameters


uint16_t color


Display Numbers

Draw an integer number.

DIS_ST7735_drawInt()
 

Parameters

 
INT_SIZE number

the integer number. The default type is int32_t that can display numbers in the range -2147483648 to 2147483647. If you need larger numbers change the INT_SIZE typedef to int64_t.

// making this larger will make the function a bit slower
typedef int32_t INT_SIZE;

int8_t nrOfDigits

is the total number of digits desired and is useful for maintaining the GUI layout. If the number to be displayed has less digits than "nrOfDigits" then it will be padded with zeros. If padding is not desired then it can be set to 0.

Example:

uint16_t ADC_results = 120;

DIS_ST7735_drawInt(ADC_results, 5);
// will display "00120" 

DIS_ST7735_drawInt(ADC_results, 3);
// will display "120"

DIS_ST7735_drawInt(ADC_results, 0);
// will display "120" 

 

Display Floats

Draw a float number.

DIS_ST7735_drawFloat()
 

Parameters:

float_number - the float number

nrOfDigits - see the drawInt()

nrOfDecimals - number of digits after the point. For example if a number is very long like this 3.14159265, setting this parameter to 2 will print 3.14.


Aligning Elements On Screen

Text alignment

The text can be aligned to the left, right and center

DIS_ST7735_textAlign()
 

Parameters:

align - can be one of the following macros: TEXT_ALIGN_LEFT, TEXT_ALIGN_RIGHT, TEXT_ALIGN_CENTER

nrOfPixels - the number of pixels that the string that will be printed would take and can be found using the DIS_ST7735_getTextWidth(string) function

Usage:

DIS_ST7735_textAlign(TEXT_ALIGN_RIGHT, DIS_ST7735_getTextWidth("Right Aligned"))
DIS_ST7735_drawString("Right Aligned")
 

Set text boundaries

This can be used to set margins around the text. The function arguments represent the margins in pixels. For example if you want all the lines of text to start from 5px from the left you set the arguments to be 5, 0, 0, 0.

DIS_ST7735_setTextBoundaries()
 

Parameters


left, right, top, bottom


Print text on the next line

 
DIS_ST7735_gotoNextLine(uint8_t x)

Move the cursor on the Y axis to start printing the text on a new line.

x -  the left margin in pixels. Can be 0 if left padding is not needed

Get text width

 
DIS_ST7735_getTextWidth(string)

Returns the with of a string of characters in pixels and can be used for text alignment.

Usage:

uint8_t textWidth = DIS_ST7735_getTextWidth("My width is")
 

Get text height

 
DIS_ST7735_getLineHeight()

Returns the height of a line of text in pixels starting from the baseline. E.g: baseline of _g_ is here _

The text height depends on the font and the text size so it doesn't need the actual string as an argument. This function is very useful in creating a menu where you need to know what line is selected for example or to clear or set the background color of a line of text.

Usage:

uint8_t textHeight = DIS_ST7735_getLineHeight()

Get position of a line of text

 
DIS_ST7735_getLineYStart(lineNr)

Returns the y coordinate in pixels of a specified line of text. This can be used with fiilRect() to set the text background or clear it.

lineNr - line number starting from 0

 

Get cursor position


DIS_ST7735_getCursorX()

Returns the cursor position on the X axis (horizontal)

DIS_ST7735_getCursorY()

Returns the cursor position on the Y axis (vertical)

 

Set cursor position

 
DIS_ST7735_setCursor(x, y)

Set the cursor position to the specified coordinates.

DIS_ST7735_setCursorX(x)
DIS_ST7735_setCursorY(y)

Set the cursor position on X or Y axis only.


Get display width and height

 
DIS_ST7735_getDisplayWidth()
DIS_ST7735_getDisplayHeight() 

Returns the display width/height in pixels. If the display is rotated in software the width/height will change accordingly. Can be used where a function expects width and height arguments.


Get last pixel coordinate

 
DIS_ST7735_getColumnCount()

Returns the number of the last pixel on the X axis. This is the equivalent of getDisplayWidth - 1. For example if you need to draw a vertical line on the last pixels the coordinate will be the display width - 1 because the first pixel starts from 0 not 1. Can be used where a function expects (x, y) coordinates.

DIS_ST7735_getRowCount()

Returns the number of the last pixel on the Y axis. This is the equivalent of getDisplayHeight - 1. 

 

Drawing Primitive Shapes

Drawing pixels

 
DIS_ST7735_writePixel(x, y, color)

Draw a single pixel at the (x, y) coordinate using the 'color' parameter. This is mainly used by the other drawing functions but it can be helpful in troubleshooting. For example if drawing a pixel at the 0,0 coordinate doesn't show anything that means the display initialization needs other settings for the particular display.

Vertical line


DIS_ST7735_drawVLine()
 

Parameters

x - horizontal position of the first point

y - vertical position of the first point

h -  line height in pixels. Can be positive or negative. Positive will continue below the first point, negative will draw above it.

color - the line color

Horizontal line


DIS_ST7735_drawHLine()

Parameters

x - horizontal position of the first point

y - vertical position of the first point

w -  line width in pixels. Can be positive or negative. Positive will continue right of the first point, negative will draw left of it.

color - the line color

Drawing a line

 
DIS_ST7735_drawLine()
 

Parameters

x0 - Start point x coordinate

y0 - Start point y coordinate

x1 - End point x coordinate

y1 - End point y coordinate

color - the line color

Rectangles

 
DIS_ST7735_drawRect()

Draw a rectangle with no fill color.

Parameters

x - top left corner on the x coordinate

y - top left corner on the y coordinate

w - width in pixels

h - height in pixels

color - 16-bit 5-6-5 color to draw with

 
DIS_ST7735_fillRect()

Fill a rectangle completely with one color. All parameters are the same as drawRect().


DIS_ST7735_drawRoundRect()

Draw a rectangle with round edges with no fill color.

Parameters

x - top left corner on the x coordinate

y - top left corner on the y coordinate

w - width in pixels

h - height in pixels

r - radius of corner rounding

color - 16-bit 5-6-5 color to draw with


DIS_ST7735_fillRoundRect()

Draw a rounded rectangle with fill color. All parameters are the same as drawRoundRect().

Circles

 
DIS_ST7735_drawCircle()

Draw a circle with no fill color.

Parameters

x - center-point x coordinate

y - center-point y coordinate

r - radius of circle

color - 16-bit 5-6-5 color to draw with


DIS_ST7735_fillCircle()

Draw a circle with filled color. All parameters are the same as drawCircle().

Triangles

 
DIS_ST7735_drawTriangle()

Draw a triangle with no fill color.

Parameters

x0 - vertex #0 x coordinate

y0 - vertex #0 y coordinate

x1 - vertex #1 x coordinate

y1 - vertex #1 y coordinate

x2 - vertex #2 x coordinate

y2 - vertex #2 y coordinate

color - 16-bit 5-6-5 color to draw with

 
DIS_ST7735_fillTriangle()

Draw a triangle with color-fill. All parameters are the same as drawTriangle(). 

Line thickness

 
DIS_ST7735_setLineThickness()

Sets the line thickness for the primitive shapes. Only works for squares and vertical/horizontal lines. 

Parameters

 
uint8_t thickness

Line thickness in pixels. Default is 1.


Bitmap Images and Icons

RGB Bitmaps from MCU flash memory

Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.

DIS_ST7735_drawRGBBitmap()

Parameters


x

top left corner x coordinate

y

top left corner y coordinate

const uint16_t bitmap[]

byte array with 16-bit color bitmap

w

width of bitmap in pixels

h

height of bitmap in pixels

If you have space on the microcontroller and only need a few small color images you can use an app to convert the image to hex numbers that can be put into an array. First step is to resize the image to a smaller size such as 36x36 or 64x64. Gimp can be used for this purpose. After pasting or loading an image go to Image -> Scale Image then export it as png or jpeg. Or use this images for testing purpose gimp mascot 36x36.png, gimp mascot 64x64.png.

To convert the image to hex numbers there is this app https://sourceforge.net/projects/lcd-image-converter/. In order to keep this article short I won't go into details on how to use the app but you can find a good tutorial here https://www.instructables.com/Converting-Images-to-Flash-Memory-Iconsimages-for-/.

Tip: if you see random pixels when displaying the image on the display, make sure the width and height parameters provided to the function are the same as image size.

Bitmaps images from memory cards

To read and display Bitmap images (16 or 24-bits) from an SD memory card there is a separate library for this purpose at this link https://www.programming-electronics-diy.xyz/2022/05/displaying-bitmap-images-on-st7735.html.

Monochrome Bitmaps/Icons

Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors. Used to draw small monochrome (single color) bitmaps, good for sprites and other mini-animations or icons. XBitMap Files (*.xbm), exported from GIMP can also be used.

DIS_ST7735_drawMonochromeBitmap()

Parameters


x

top left corner x coordinate

y

top left corner y coordinate

bitmap[]

byte array with monochrome bitmap

w

width of bitmap in pixels

h

height of bitmap in pixels

color

16-bit 5-6-5 color to draw with

bgColor

the background color

tr

transparency. If 1 the background will be transparent

Creating Monochrome Icons in GIMP for TFT Displays

Next I will be showing how to make a monochrome 1-bit icon bitmap in GIMP - a free application. This type of icons are very useful in a microcontroller based GUI because they take less space - 1bit per pixel - and are easy to make.

First create a new document with the width and height of the desired icon; 16 by 24 in this example and set Fill with: Background color. The rest of the settings can be the default ones.

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 01

Then convert the image to a 1-bit palette going to Image -> Mode -> Indexed and select Use black and white (1-bit) palette.

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 02

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 03

Next go to Image-> Configure Grid and set Foreground color to black, Background color to white and Horizontal and Vertical spacing to 1 by 1 pixels.

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 04

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 05

To display the grid go to View-> Show Grid

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 06

The background must be white. In case it is black use the paint bucket to color it white. Then using the Pencil Tool we can draw some pixels. But first modify some of the Pencil Tool settings - Opacity: 100%, Size: 1, Dynamics: Off. 

Tip: in case you need to erase a pixel use the X key to switch between black and white colors. Use the paint bucket to erase all.

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 07

As an example I drew a battery symbol that I use in the Universal Battery Charger project. The fill lines can be made using the drawRectangle function. After the icon is ready use Export As batteryIcon.xbm. The name can be anything but the extension must be .xbm

Creating monochrome 1bit bitmap icons in Gimp for TFT displays 08
Creating monochrome 1bit bitmap icons in Gimp for TFT displays 09

Finally change the extension of the generated file to .h and open it and place the code in the main.c file that should look like this:

const uint8_t batterySymbolBitmap[] PROGMEM = {
	0xc0, 0x03, 0xc0, 0x03, 0xff, 0xff, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
	0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
	0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80,
	0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x1f, 0xf8
};

const means the program doesn't need to modify the array, helping the compiler save some space and PROGMEM puts the array in the Flash space memory not RAM.

DIS_ST7735_drawMonochromeBitmap(10, 30, batterySymbolBitmap, 16, 24, ST77XX_GREEN, 0, true);

Tip: if you wish to know the position of GUI elements relative to each other or if they fit on the display, you could create a similar file but with the size of the display's width and height. This can be easier in Inkscape.

Array of Icons - Icon Sets

To better organize the icons you can place them in an array and select them using an enum like so:

enum GUIIconsIDX{
    PLAY_BTN,
    PAUSE_BTN	
};

const uint8_t GUIIcons[][36] PROGMEM = {
    {   // Play Button
	0x03, 0x00, 0x0f, 0x00, 0x3f, 0x00, 0xff, 0x00, 0xff, 0x03, 0xff, 0x0f,
	0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x0f, 0xff, 0x03,
	0xff, 0x00, 0x3f, 0x00, 0x0f, 0x00, 0x03, 0x00
    },
    {   // Pause Button
        0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe,
	0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe,
	0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe
    }
};
 
DIS_ST7735_drawMonochromeBitmap(10, 30, GUIIcons[PLAY_BTN], 16, 16, ST77XX_GREEN, 0, true);
DIS_ST7735_drawMonochromeBitmap(40, 30, GUIIcons[PAUSE_BTN], 16, 16, ST77XX_GREEN, 0, true); 


Reading data from the ST7735 display driver

DIS_ST7735_readManufacturerID()
DIS_ST7735_readVersionID()
DIS_ST7735_readDriverID()

The returned data is of the integer type.


Extra Functions

Turn display on/off

DIS_ST7735_enableDisplay(bool enable)

If enable is 1 or true the display will turn ON, if 0 or false the display will turn OFF. If the backlight pin is connected to the microcontroller and defined, this will also control the backlight.

Idle Mode

DIS_ST7735_idleMode(bool enable)

Change whether idle mode is on or off. In this mode, part of the display is used but with 8 colors.

enable - true for idle mode ON, false for idle mode OFF

Sleep Mode

DIS_ST7735_enableSleep(bool enable)

Change whether sleep mode is on or off. In this mode, the DC: DC converter, internal oscillator and panel driver circuit are stopped. Only the MCU interface and memory works with VDDI power supply. Contents of the memory are safe.

enable - true if you want sleep mode ON, false OFF

Backlight On/Off

DIS_ST7735_backlightOn()
DIS_ST7735_backlightOff()

If the backlight pin is connected to the microcontroller and defined, this macro functions can be used to turn the backlight on or off.

Rotate the display

void DIS_ST7735_setRotation()

Sometimes in a project a physical rotation of the display is not possible so this function can be handy. It can also be used to draw text or numbers in a different direction. This will not rotate what is already on the screen but will change the coordinate system for any new drawings. 

Parameters


uint8_t rotation

can be one of the following macros: 

ROTATE_DEGREE_0

ROTATE_DEGREE_90

ROTATE_DEGREE_180

ROTATE_DEGREE_270

Invert colors

DIS_ST7735_invertDisplay(bool invert)

Invert the colors of the display (if supported by hardware).

invert - true = inverted display, false = normal display


Library Configuration

I/O Pins

Before using the library the input/output pins must be defined to match the microcontroller. These defines can be found and edited at the beginning of the library file. 

Multiple SPI devices

If you have more than one SPI devices, such as the display and an SD card, set their CS (Chip Select) pins as output high before using any initialization functions, otherwise while one is being initialized another device could start to communicate creating conflicts on the communication bus.

Display dimensions: width and height

Modify these two defines to match your display:

#define DISPLAY_WIDTH		128
#define DISPLAY_HEIGHT		160
 

Basic Code Example

// Include the library
#include "DIS_ST7735.h"

// Include the font
#include "Fonts/FreeSans9pt7b.h"

int main(void){
	
	// Init function
	DIS_ST7735_displayInit();
	
	// Clear the display with the desired background color
	DIS_ST7735_fillScreen(ST77XX_BLACK);
	
	// Set the font
	DIS_ST7735_setFont(&FreeSans9pt7b);
	
	// Set the font color
	DIS_ST7735_setFontColor(ST77XX_RED);
	
	// Set the cursor 5px from the left and a distance 
	// equal with the text height from the top
	DIS_ST7735_setCursor(5, DIS_ST7735_getLineHeight());
	
	// Draw this original string
	DIS_ST7735_drawString("Hello");
	
	// Move the cursor to the next line 5px from left
	DIS_ST7735_gotoNextLine(5);
	
	DIS_ST7735_drawString("PI = ");
	DIS_ST7735_drawFloat(3.14, 0, 2);
	
	// Draw a number in a loop
	uint8_t i = 0;
	
	while(1){
		// Set cursor to the same position after each loop
		// 5px from left and 3 text lines from top
		DIS_ST7735_setCursor(5, DIS_ST7735_getLineHeight() * 3);
		
		// fillRect() is used with the same color as the background
		// to clear the previous number and draw a new one. Use a light color as yellow
		// to debug de rectangle position. The Y position is getCursorY() minus
		// a line height with 4px down to not erase the upper line
		// - width is DIS_ST7735_getTextWidth("0") * 3 because the number has maximum 3 digits (255)
		// - height parameter is DIS_ST7735_getLineHeight()
		DIS_ST7735_fillRect(5, DIS_ST7735_getCursorY() - DIS_ST7735_getLineHeight() + 4, DIS_ST7735_getTextWidth("0") * 3, DIS_ST7735_getLineHeight(), ST77XX_BLACK);
		DIS_ST7735_drawInt(i, 0);
		i++;
		_delay_ms(200);
	}
}


Download

Change log and license can be found at the beginning of the files.
v2.0 DIS_ST7735 library Folder can be downloaded as a zip file
Changelog
v2.0 06-02-2024:
- Included support for newer UPDI AVR devices.
v1.5 - Added software SPI for cases when MISO pin is used for D/C pin, since MISO was not used in 1 wire SPI but was still being used by hardware SPI.
Other Links

ST7735 datasheet

fontconvert.zip Contains fontconvert.exe compiled by myself on Windows 10 used to create custom fonts.
Update: seems that Google realized this is not malware.
Since google drive thinks this is malware, the file could not be downloaded so I added this version using the 1234 password. This is a false positive since the only thing the file does is to convert a font to a C header file readable by the microcontroller.

Arial fonts used in the code example.zip

2 comments:

  1. fontconvert.zip - this is the fontcon......
    Sorry, this file is infected with a virus.
    Infected files can only be downloaded by the owner.

    ReplyDelete
    Replies
    1. Thanks for letting me know. I wasn't aware that google drive gives that warning but I assure you that is a false positive.
      Here is the result from virustotal:
      https://www.virustotal.com/gui/file/06eab4648491631b9749c42f4cd3638054dc9a7902c95aaa6a5f7aeecaba677b?nocache=1
      4 out of 61 scanners flagged as a malware. Don't know why but it's a false positive. Maybe it happens with software that is not digitally signed. You can run it in a sandbox, give it to an expert to analyze it or compile another one.

      Delete