ST7735R mini library – saving writing/erasing cycles

When you design your graphics for your TFT display, you will need a lot of modifications during the process. That would mean that at every change you would have had the microcontroller programmed again, burning the writing/erasing cycles at an alarming speed.

Considering this, some companies are offering you PC applications that helps you visually design your graphics without wasting your microcontroller. It might be that you can’t afford the money or the application does not have your display in its database.

Fortunately, there is libgd, a graphics library that creates images on the fly on which the coordinates of the pixels are identical with my Adafruit 160×80 0.96″ TFT display. All I had to do, was to adapt the font functions from the ST7735R mini library to work with libgd and I got a PC application under Linux that was modified and used every time I decided that the graphics are not good enough and needs a change. The application provided me with the images at the needed resolution, as it would look on the real TFT (in this case, main menu graphics for my SLR Film Camera project):

undefined

Of course, that is temporary and surely might change in time (the graphics). And the code of the application (which BTW, is a console application – sorry) is below but can be downloaded also from here. You can make as many changes as you want, compile the application (forgot to say that is an Anjuta IDE project, so you have to have that installed on your Linux) and execute it without touching the microcontroller. You will find the generated JPEG images in the same folder as the application executable. Neat? If you ask me, yes, it is! Well, just to be sure that I am understood, these images are not to be loaded on your microcontroller, they just simulate the look of your code that you will write on the microcontroller. Right? Good! Now the code (that will be crippled by the wordpress for sure, so is just to have a look at it, for the real thing, download the archive from the specified link):

/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*-  */
/*
 * main.c
 * Copyright (C) 2020 Vasile Guta-Ciucur 
 *
 * Adapted font functions from @o-m-d from https://github.com/o-m-d/st7735_spi_stm32
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name ``Vasile Guta-Ciucur'' nor the name of any other
 *    contributor may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 * 
 * slr_exposure IS PROVIDED BY Vasile Guta-Ciucur ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL Vasile Guta-Ciucur OR ANY OTHER CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "stdio.h"
#include "stdint.h"
#include "stdbool.h"
#include "string.h"
#include "gd.h"
#include "font5x7.h"
#include "font7x11.h"

/* Declare the image */
gdImagePtr im;
int scr_width = 160;
int scr_height = 80;


void PutChar5x7(uint8_t scale, int X, int Y, uint8_t chr, int color, int bgcolor)
{
  int i,j;
  uint8_t buffer[5];

  if ((chr >= 0x20) && (chr <= 0x7F)) {
    // ASCII[0x20-0x7F]
    memcpy(buffer,&Font5x7[(chr - 32) * 5], 5);
  } else if (chr >= 0xA0) {
    // CP1251[0xA0-0xFF]
    memcpy(buffer,&Font5x7[(chr - 64) * 5], 5);
  } else {
    // unsupported symbol
    memcpy(buffer,&Font5x7[160], 5);
  }

  // scale equals 1 drawing faster
  if (scale == 1) {
    gdImageFilledRectangle(im, X, Y, X + 5, Y + 7, bgcolor);
    for (j = 0; j < 7; j++) {
      for (i = 0; i < 5; i++) {
        if ((buffer[i] >> j) & 0x01) {
          gdImageSetPixel(im, i+X, j+Y, color);
        }
      }
    }
  } else {
    for (j = 0; j < 7; j++) {
      for (i = 0; i < 5; i++) {
        // pixel group
        gdImageFilledRectangle(im, X + (i * scale), Y + (j * scale), X + (i * scale) + scale - 1, Y + (j * scale) + scale - 1, ((buffer[i] >> j) & 0x01) ? color : bgcolor);
      }
      gdImageFilledRectangle(im, X + (i * scale), Y + (j * scale), X + (i * scale) + scale - 1, Y + (j * scale) + scale - 1, bgcolor);
    }
    gdImageFilledRectangle(im, X, Y + (j * scale), X + (i * scale) + scale - 1, Y + (j * scale) + scale - 1, bgcolor);
  }
}

void PutStr5x7(uint8_t scale, int X, int Y, char *str, int color, int bgcolor)
{
  // scale equals 1 drawing faster
  if (scale == 1) {
    while (*str) {
      PutChar5x7(scale, X,Y,*str++,color,bgcolor);
      if (X < scr_width - 6) {
        X += 6;
      } else if (Y < scr_height - 8) {
        X = 0;
        Y += 8;
      } else {
        X = 0;
        Y = 0;
      }
    };
  } else {
    while (*str) {
      PutChar5x7(scale, X,Y,*str++,color,bgcolor);
      if (X < scr_width - (scale*5) + scale) {
        X += (scale * 5) + scale;
      } else if (Y < scr_height - (scale * 7) + scale) {
        X = 0;
        Y += (scale * 7) + scale;
      } else {
        X = 0;
        Y = 0;
      }
    };
  }
}

void PutChar7x11(int X, int Y, uint8_t chr, int color, int bgcolor)
{
  int i,j;
  uint8_t buffer[11];

  if ((chr >= 0x20) && (chr <= 0x7F)) {
    // ASCII[0x20-0x7F]
    memcpy(buffer,&Font7x11[(chr - 32) * 11], 11);
  } else if (chr >= 0xA0) {
    // CP1251[0xA0-0xFF]
    memcpy(buffer,&Font7x11[(chr - 64) * 11], 11);
  } else {
    // unsupported symbol
    memcpy(buffer,&Font7x11[160], 11);
  }

  gdImageFilledRectangle(im, X, Y, X + 7, Y + 11,bgcolor);
  for (i = 0; i < 11; i++) {
    for (j = 0; j < 7; j++) {
      if ((buffer[i] >> j) & 0x01) {
        gdImageSetPixel(im, j+X, i+Y, color);
      }
    }
  }
}

void PutStr7x11(uint8_t X, uint8_t Y, char *str, uint16_t color, uint16_t bgcolor)
{
  while (*str) {
    PutChar7x11(X,Y,*str++,color,bgcolor);
    if (X < scr_width - 8) {
      X += 8;
    } else if (Y < scr_height - 12) {
      X = 0;
      Y += 12;
    } else {
      X = 0;
      Y = 0;
    }
  };
}

int main() {
  FILE *jpegout;	

  int black;
  int white;
  int cyan;
  int yellow;
  int green;
  int red;
  int orange;


  /* First screen:  */
  im = gdImageCreate(scr_width, scr_height);

  /* Allocate the color black (red, green and blue all minimum).
    Since this is the first color in a new image, it will
    be the background color. */
  black = gdImageColorAllocate(im, 0, 0, 0);

  white  = gdImageColorAllocate(im, 255, 255, 255);
  cyan   = gdImageColorAllocate(im, 0, 255, 255);
  yellow = gdImageColorAllocate(im, 255, 255, 0);
  green  = gdImageColorAllocate(im, 0, 255, 0);
  red    = gdImageColorAllocate(im, 255, 0, 0);
  orange = gdImageColorAllocate(im, 255, 140, 0);

  //MENU A
  //================================================
  gdImageFilledRectangle(im, 0, 0, scr_width-1, scr_height-1, black);
  //PutStr7x11(1, 1, "APERTURE", black, yellow);
  PutStr5x7(1, 3, 3, "APERTURE PRIORITY", white, black);
  gdImageLine(im, 0, 13, 159, 13, red);
  PutStr5x7(7, 20, 22, "-A-", white, black);
  //gdImageRectangle(im, 5, 37, scr_width-1-5, scr_height-1-5, yellow); 
  //gdImageFilledRectangle(im, 5+2, 37+2, scr_width-1-5-2, scr_height-1-5-2, orange);
  jpegout = fopen("menu_a.jpg", "wb");
  gdImageJpeg(im, jpegout, 100);
  /* Close the files. */
  fclose(jpegout);
  //================================================

  //MENU S
  //================================================
  gdImageFilledRectangle(im, 0, 0, scr_width-1, scr_height-1, black);
  //PutStr7x11(1, 1, "SHUTTER", black, yellow);
  PutStr5x7(1, 3, 3, "SHUTTER PRIORITY", white, black);
  gdImageLine(im, 0, 13, 159, 13, red);
  PutStr5x7(7, 20, 22, "-S-", white, black);
  //gdImageRectangle(im, 5, 37, scr_width-1-5, scr_height-1-5, yellow); 
  //gdImageFilledRectangle(im, 5+2, 37+2, scr_width-1-5-2, scr_height-1-5-2, orange);
  jpegout = fopen("menu_s.jpg", "wb");
  gdImageJpeg(im, jpegout, 100);
  /* Close the files. */
  fclose(jpegout);
  //================================================


  // MENU M
  //========================================
  gdImageFilledRectangle(im, 0, 0, scr_width-1, scr_height-1, black);
  //PutStr7x11(1, 1, "MANUAL", black, yellow);
  PutStr5x7(1, 3, 3, "MANUAL CONTROLS", white, black);
  gdImageLine(im, 0, 13, 159, 13, red);
  PutStr5x7(7, 20, 22, "-M-", white, black);
  //gdImageRectangle(im, 5, 37, scr_width-1-5, scr_height-1-5, yellow); 
  //gdImageFilledRectangle(im, 5+2, 37+2, scr_width-1-5-2, scr_height-1-5-2, orange);
  jpegout = fopen("menu_m.jpg", "wb");
  gdImageJpeg(im, jpegout, 100);
  /* Close the files. */
  fclose(jpegout);
  //================================================

  //MENU ISO
  //================================================
  gdImageFilledRectangle(im, 0, 0, scr_width-1, scr_height-1, black);
  //PutStr7x11(1, 1, "SET ISO", black, yellow);
  PutStr5x7(1, 3, 3, "SET ISO", white, black);
  gdImageLine(im, 0, 13, 159, 13, red);
  PutStr5x7(7, 20, 22, "ISO", white, black);
  //gdImageRectangle(im, 5, 37, scr_width-1-5, scr_height-1-5, yellow); 
  //gdImageFilledRectangle(im, 5+2, 37+2, scr_width-1-5-2, scr_height-1-5-2, orange);
  jpegout = fopen("menu_iso.jpg", "wb");
  gdImageJpeg(im, jpegout, 100);
  /* Close the files. */
  fclose(jpegout);
  //================================================

  //MENU LUX
  //================================================
  gdImageFilledRectangle(im, 0, 0, scr_width-1, scr_height-1, black);
  //PutStr7x11(1, 1, "SEE LUX", black, yellow);
  PutStr5x7(1, 3, 3, "SEE LUX VALUES", white, black);
  gdImageLine(im, 0, 13, 159, 13, red);
  PutStr5x7(7, 20, 22, "LUX", white, black);
  //gdImageRectangle(im, 5, 37, scr_width-1-5, scr_height-1-5, yellow); 
  //gdImageFilledRectangle(im, 5+2, 37+2, scr_width-1-5-2, scr_height-1-5-2, orange);
  jpegout = fopen("menu_lux.jpg", "wb");
  gdImageJpeg(im, jpegout, 100);
  /* Close the files. */
  fclose(jpegout);
  //================================================
  


  
  /* Destroy the image in memory. */
  gdImageDestroy(im);
}


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.