Continuing the STM8 Expedition

STM8S105 Discovery

TFT Display – ST7735

Alphanumeric LCD are well-suited for most applications that require no graphical objects to be projected on a display screen. However, to make interfaces interactive and user-friendly, designers sometimes like things to be projected graphically. For example, consider an oscilloscope. In such cases, we need to use a graphical LCD (GLCD) or TFT display. Compared to GLCDs, TFTs are much more interactive, smarter and cheaper. Most GLCDs are monochrome and fat while TFTs are just the opposites. Because of these reasons, TFTs are more popular than GLCDs.

TFT

At present TFT displays are very common in the embedded-system market. There are many models of TFT displays, varying in screen size, resolution and other properties. ILI9325, IL9341, SSD1289, SSD1963, etc. are a few examples of common TFT display chips. However, most these TFT drivers need about sixteen plus GPIOs to function as they use 8080 display interface to communicate with host devices. ST7735-based TFT display stands differently in this regard. It needs SPI instead of 8080 display interface and it is good enough for most application. Adding a resistive touch screen on top of the display and SD card support will make it smarter.

Hardware Connection

TFT

Code Example

font.h

static const unsigned char font[][5] =
{
     {0x00, 0x00, 0x00, 0x00, 0x00} // 20
    ,{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 ?
    ,{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, 0x18, 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 ?
    ,{0x78, 0x46, 0x41, 0x46, 0x78} // 7f ?
};

 

ST7735.h

#include "STM8S.h"
#include "font.h"


#define SPI_PORT                                 GPIOC
#define CTL_PORT                                 GPIOD

#define CS_pin                                  GPIO_PIN_7
#define RS_pin                                  GPIO_PIN_5
#define RST_pin                                 GPIO_PIN_6
#define SCK_pin                                 GPIO_PIN_5
#define SDA_pin                                 GPIO_PIN_6

#define ST7735_NOP                              0x00
#define ST7735_SWRESET                          0x01
#define ST7735_RDDID                            0x04
#define ST7735_RDDST                            0x09
#define ST7735_RDDPM                            0x0A
#define ST7735_RDD_MADCTL                       0x0B
#define STT7735_RDD_COLMOD                      0x0C
#define ST7735_RDDIM                            0x0D
#define ST7735_RDDSM                            0x0E

#define ST7735_SLPIN                            0x10
#define ST7735_SLPOUT                           0x11
#define ST7735_PTLON                            0x12
#define ST7735_NORON                            0x13

#define ST7735_INVOFF                           0x20
#define ST7735_INVON                            0x21
#define ST7735_GAMSET                           0x26
#define ST7735_DISPOFF                          0x28
#define ST7735_DISPON                           0x29
#define ST7735_CASET                            0x2A
#define ST7735_RASET                            0x2B
#define ST7735_RAMWR                            0x2C
#define ST7735_RAMRD                            0x2E

#define ST7735_PTLAR                            0x30
#define ST7735_TEOFF                            0x34
#define ST7735_TEON                             0x35
#define ST7735_MADCTL                           0x36
#define ST7735_IDMOFF                           0x38
#define ST7735_IDMON                            0x39
#define ST7735_COLMOD                           0x3A

#define ST7735_RDID1                            0xDA
#define ST7735_RDID2                            0xDB
#define ST7735_RDID3                            0xDC
#define ST7735_RDID4                            0xDD

#define ST7735_FRMCTR1                          0xB1
#define ST7735_FRMCTR2                          0xB2
#define ST7735_FRMCTR3                          0xB3
#define ST7735_INVCTR                           0xB4
#define ST7735_DISSET5                          0xB6

#define ST7735_PWCTR1                           0xC0
#define ST7735_PWCTR2                           0xC1
#define ST7735_PWCTR3                           0xC2
#define ST7735_PWCTR4                           0xC3
#define ST7735_PWCTR5                           0xC4
#define ST7735_VMCTR1                           0xC5

#define ST7735_RDID1                            0xDA
#define ST7735_RDID2                            0xDB
#define ST7735_RDID3                            0xDC
#define ST7735_RDID4                            0xDD

#define ST7735_PWCTR6                           0xFC

#define ST7735_GMCTRP1                          0xE0
#define ST7735_GMCTRN1                          0xE1

#define   BLACK                                 0x0000
#define   BLUE                                  0x001F
#define   RED                                   0xF800
#define   GREEN                                 0x07E0
#define   CYAN                                  0x07FF
#define   MAGENTA                               0xF81F
#define   YELLOW                                0xFFE0
#define   WHITE                                 0xFFFF

#define   MADCTL_MY                             0x80
#define   MADCTL_MX                             0x40
#define   MADCTL_MV                             0x20
#define   MADCTL_ML                             0x10
#define   MADCTL_RGB                            0x08
#define   MADCTL_MH                             0x04

#define ST7735_TFTWIDTH                         128
#define ST7735_TFTLENGTH                        160

#define CMD                                     0x0
#define DAT                                     0x1

#define SQUARE                                  0x00
#define ROUND                                   0x01

#define NO                                      0x00
#define YES                                     0x01


extern unsigned int width;
extern unsigned int length;


unsigned int Swap_Colour(unsigned int colour);
unsigned int Color565(unsigned char r, unsigned char g, unsigned char b);
void SPI_setup(void);
void ST7735_HW_init(void);
void ST7735_Write(unsigned char value, unsigned char mode);
void ST7735_Reset(void);
void ST7735_init(void);
void ST7735_Word_Write(unsigned int value);
void ST7735_Set_Addr_Window(signed int xs, signed int ys, signed int xe, signed int ye);
void ST7735_RAM_Address_Set(void);
void ST7735_Invert_Display(unsigned char i);
void ST7735_Set_Rotation(unsigned char m);
void TFT_fill(unsigned int colour);
void Draw_Pixel(signed int x_pos, signed int y_pos, unsigned int colour);
void Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned int colour);
void Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char type, unsigned int colour, unsigned int back_colour);
void Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned int colour);
void Draw_V_Line(signed int x1, signed int y1, signed int y2, unsigned colour);
void Draw_H_Line(signed int x1, signed int x2, signed int y1, unsigned colour);
void Draw_Triangle(signed int x1, signed int y1, signed int x2, signed int y2, signed int x3, signed int y3, unsigned char fill, unsigned int colour);
void Draw_Font_Pixel(signed int x_pos, signed int y_pos, unsigned int colour, unsigned char pixel_size);
void print_char(signed int x_pos, signed int  y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, char ch);
void print_str(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, char *ch);
void print_C(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value);
void print_I(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value);
void print_D(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, unsigned int value, unsigned char points);
void print_F(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, float value, unsigned char points);

 

ST7735.c

#include "ST7735.h"


extern unsigned int width;
extern unsigned int length;


unsigned int Swap_Colour(unsigned int colour)
{
    return ((colour << 0x000B) | (colour & 0x07E0) | (colour >> 0x000B));
}


unsigned int Color565(unsigned char r, unsigned char g, unsigned char b)
{
    return (((r & 0xF8) << 0x08) | ((g & 0xFC) << 0x03) | (b >> 0x03));
}


void SPI_setup(void)
{
    SPI_DeInit();

    SPI_Init(SPI_FIRSTBIT_MSB,
                  SPI_BAUDRATEPRESCALER_2,
                  SPI_MODE_MASTER,
                  SPI_CLOCKPOLARITY_HIGH,
                  SPI_CLOCKPHASE_1EDGE,
                  SPI_DATADIRECTION_1LINE_TX,
                  SPI_NSS_SOFT,
                  0x00);

    SPI_Cmd(ENABLE);
}


void ST7735_HW_init(void)
{     
    GPIO_Init(SPI_PORT, ((GPIO_Pin_TypeDef)(SCK_pin | SDA_pin)),     GPIO_MODE_OUT_PP_HIGH_FAST);
    GPIO_Init(CTL_PORT, ((GPIO_Pin_TypeDef)(CS_pin | RS_pin | RST_pin)), GPIO_MODE_OUT_PP_HIGH_FAST);
    SPI_setup();
    delay_ms(10);   
}


void ST7735_Write(unsigned char value, unsigned char mode)
{
    while(SPI_GetFlagStatus(SPI_FLAG_BSY));
    GPIO_WriteLow(CTL_PORT, CS_pin);

        switch(mode)
    {
        case CMD:
        {
            GPIO_WriteLow(CTL_PORT, RS_pin);
            break;
        }

        case DAT:
        {
            GPIO_WriteHigh(CTL_PORT, RS_pin);
            break;
        }
    }

    SPI_SendData(value);
    while(!SPI_GetFlagStatus(SPI_FLAG_TXE));

    GPIO_WriteHigh(CTL_PORT, CS_pin);
}


void ST7735_Reset(void)
{
    GPIO_WriteLow(CTL_PORT, RST_pin);
    delay_ms(2);
    GPIO_WriteHigh(CTL_PORT, RST_pin);
    delay_ms(2);
}


void ST7735_init(void)
{
    ST7735_HW_init();
    ST7735_Reset();

    ST7735_Write(ST7735_SWRESET, CMD);
    delay_us(150);
    ST7735_Write(ST7735_SLPOUT, CMD);
    delay_us(150);

    ST7735_Write(ST7735_FRMCTR1, CMD);
    ST7735_Write(0x01, DAT);
    ST7735_Write(0x2C, DAT);
    ST7735_Write(0x2D, DAT);

    ST7735_Write(ST7735_FRMCTR2, CMD);
    ST7735_Write(0x01, DAT);
    ST7735_Write(0x2C, DAT);
    ST7735_Write(0x2D, DAT);

    ST7735_Write(ST7735_FRMCTR3, CMD);
    ST7735_Write(0x01, DAT);
    ST7735_Write(0x2C, DAT);
    ST7735_Write(0x2D, DAT);
    ST7735_Write(0x01, DAT);
    ST7735_Write(0x2C, DAT);
    ST7735_Write(0x2D, DAT);

    ST7735_Write(ST7735_INVCTR, CMD);
    ST7735_Write(0x07, DAT);

    ST7735_Write(ST7735_PWCTR1, CMD);
    ST7735_Write(0xA2, DAT);
    ST7735_Write(0x02, DAT);
    ST7735_Write(0x84, DAT);

    ST7735_Write(ST7735_PWCTR1, CMD);
    ST7735_Write(0xC5, DAT);

    ST7735_Write(ST7735_PWCTR2, CMD);
    ST7735_Write(0x0A, DAT);
    ST7735_Write(0x00, DAT);

    ST7735_Write(ST7735_PWCTR3, CMD);
    ST7735_Write(0x8A, DAT);
    ST7735_Write(0x2A, DAT);

    ST7735_Write(ST7735_PWCTR4, CMD);
    ST7735_Write(0x8A, DAT);
    ST7735_Write(0xEE, DAT);

    ST7735_Write(ST7735_PWCTR5, CMD);
    ST7735_Write(0x0E, DAT);

    ST7735_Write(ST7735_VMCTR1, CMD);
    ST7735_Write(0x00, DAT);

    ST7735_Write(ST7735_COLMOD, CMD);
    ST7735_Write(0x05, DAT);

    ST7735_Write(ST7735_MADCTL, CMD);
    ST7735_Write(0xC8, DAT);

    ST7735_RAM_Address_Set();

    ST7735_Write(ST7735_GMCTRP1, CMD);
    ST7735_Write(0x02, DAT);
    ST7735_Write(0x1C, DAT);
    ST7735_Write(0x07, DAT);
    ST7735_Write(0x12, DAT);
    ST7735_Write(0x37, DAT);
    ST7735_Write(0x32, DAT);
    ST7735_Write(0x29, DAT);
    ST7735_Write(0x2D, DAT);
    ST7735_Write(0x29, DAT);
    ST7735_Write(0x25, DAT);
    ST7735_Write(0x2B, DAT);
    ST7735_Write(0x39, DAT);
    ST7735_Write(0x00, DAT);
    ST7735_Write(0x01, DAT);
    ST7735_Write(0x03, DAT);
    ST7735_Write(0x10, DAT);

    ST7735_Write(ST7735_GMCTRN1, CMD);
    ST7735_Write(0x03, DAT);
    ST7735_Write(0x1D, DAT);
    ST7735_Write(0x07, DAT);
    ST7735_Write(0x06, DAT);
    ST7735_Write(0x2E, DAT);
    ST7735_Write(0x2C, DAT);
    ST7735_Write(0x29, DAT);
    ST7735_Write(0x2D, DAT);
    ST7735_Write(0x2E, DAT);
    ST7735_Write(0x2E, DAT);
    ST7735_Write(0x37, DAT);
    ST7735_Write(0x3F, DAT);
    ST7735_Write(0x00, DAT);
    ST7735_Write(0x00, DAT);
    ST7735_Write(0x02, DAT);
    ST7735_Write(0x10, DAT);

    ST7735_Write(ST7735_NORON, CMD);
    delay_ms(10);

    ST7735_Write(ST7735_DISPON, CMD);
    delay_ms(100);

    ST7735_Write(ST7735_RAMWR, CMD);
    delay_ms(100);
}


void ST7735_Word_Write(unsigned int value)
{
    ST7735_Write(((value & 0xFF00) >> 0x08), DAT);
    ST7735_Write((value & 0x00FF), DAT);
}


void ST7735_Set_Addr_Window(signed int xs, signed int ys, signed int xe, signed int ye)
{
    ST7735_Write(ST7735_CASET, CMD);
    ST7735_Write(0x00, DAT);
    ST7735_Write(xs, DAT);
    ST7735_Write(0x00, DAT);
    ST7735_Write(xe, DAT);

    ST7735_Write(ST7735_RASET, CMD);
    ST7735_Write(0x00, DAT);
    ST7735_Write(ys, DAT);
    ST7735_Write(0x00, DAT);
    ST7735_Write(ye, DAT);

    ST7735_Write(ST7735_RAMWR, CMD);
}


void ST7735_RAM_Address_Set(void)
{
     ST7735_Set_Addr_Window(0x00, 0x00, 0x7F, 0x9F);
}


void ST7735_Invert_Display(unsigned char i)
{     
     ST7735_Write(i, CMD);
}


void ST7735_Set_Rotation(unsigned char m)
{
    unsigned char rotation = 0x00;

    ST7735_Write(ST7735_MADCTL, CMD);
    rotation = (m % 4);

    switch(rotation)
    {
        case 0:
        {
            ST7735_Write((MADCTL_MX | MADCTL_MY | MADCTL_RGB), DAT);
            width  = ST7735_TFTWIDTH;
            length = ST7735_TFTLENGTH;
            break;
        }
        case 1:
        {
            ST7735_Write((MADCTL_MY | MADCTL_MV | MADCTL_RGB), DAT);
            width  = ST7735_TFTLENGTH;
            length = ST7735_TFTWIDTH;
            break;
        }
        case 2:
        {
            ST7735_Write((MADCTL_RGB), DAT);
            width = ST7735_TFTWIDTH;
            length = ST7735_TFTLENGTH;
            break;
        }
        case 3:
        {
            ST7735_Write((MADCTL_MX | MADCTL_MV | MADCTL_RGB), DAT);
            width = ST7735_TFTLENGTH;
            length = ST7735_TFTWIDTH;
            break;
        }
    }
}


void TFT_fill(unsigned int colour)
{
    signed int i = 0x00;
    signed int j = 0x00;

    ST7735_Set_Addr_Window(0, 0, (width - 1), (length - 1));

    for(j = length; j > 0; j--)
    {
        for(i = width; i > 0; i--)
        {
            ST7735_Word_Write(colour);
        }
    }
}


void Draw_Pixel(signed int x_pos, signed int y_pos, unsigned int colour)
{
     ST7735_Set_Addr_Window(x_pos, y_pos, (1 + x_pos), (1 + y_pos));
     ST7735_Word_Write(colour);
}


void Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned int colour)
{
    signed int dx = 0x0000;
    signed int dy = 0x0000;
    signed int stepx = 0x0000;
    signed int stepy = 0x0000;
    signed int fraction = 0x0000;

    dy = (y2 - y1);
    dx = (x2 - x1);

    if (dy < 0)
    {
        dy = -dy;
        stepy = -1;
    }
    else
    {
        stepy = 1;
    }

    if (dx < 0)
    {
        dx = -dx;
        stepx = -1;
    }
    else
    {
        stepx = 1;
    }

    dx <<= 0x01;
    dy <<= 0x01;

    Draw_Pixel(x1, y1, colour);

    if (dx > dy)
    {
        fraction = (dy - (dx >> 1));
        while (x1 != x2)
        {
            if (fraction >= 0)
            {
                y1 += stepy;
                fraction -= dx;
            }
            x1 += stepx;
            fraction += dy;

            Draw_Pixel(x1, y1, colour);
        }
    }
    else
    {
        fraction = (dx - (dy >> 1));

        while (y1 != y2)
        {
            if (fraction >= 0)
            {
                x1 += stepx;
                fraction -= dy;
            }
            y1 += stepy;
            fraction += dx;
            Draw_Pixel(x1, y1, colour);
        }
    }
}


void Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char type, unsigned int colour, unsigned int back_colour)
{
     unsigned char i = 0x00;
     unsigned char xmin = 0x00;
     unsigned char xmax = 0x00;
     unsigned char ymin = 0x00;
     unsigned char ymax = 0x00;

     if(fill != NO)
     {
        if(x1 < x2)
        {
           xmin = x1;
           xmax = x2;
        }
        else
        {
           xmin = x2;
           xmax = x1;
        }

        if(y1 < y2)
        {
           ymin = y1;
           ymax = y2;
        }
        else
        {
           ymin = y2;
           ymax = y1;
        }

        for(; xmin <= xmax; ++xmin)
        {
             for(i = ymin; i <= ymax; ++i)
             {
                 Draw_Pixel(xmin, i, colour);
             }
         }
     }

     else
     {
        Draw_Line(x1, y1, x2, y1, colour);
        Draw_Line(x1, y2, x2, y2, colour);
        Draw_Line(x1, y1, x1, y2, colour);
        Draw_Line(x2, y1, x2, y2, colour);
     }

     if(type != SQUARE)
     {
         Draw_Pixel(x1, y1, back_colour);
         Draw_Pixel(x1, y2, back_colour);
         Draw_Pixel(x2, y1, back_colour);
         Draw_Pixel(x2, y2, back_colour);
     }
}


void Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned int colour)
{
   signed int a = 0x0000;
   signed int b = 0x0000;
   signed int p = 0x0000;

   b = radius;
   p = (1 - b);

   do
   {
        if(fill != NO)
        {
            Draw_Line((xc - a), (yc + b), (xc + a), (yc + b), colour);
            Draw_Line((xc - a), (yc - b), (xc + a), (yc - b), colour);
            Draw_Line((xc - b), (yc + a), (xc + b), (yc + a), colour);
            Draw_Line((xc - b), (yc - a), (xc + b), (yc - a), colour);
        }
        else
        {
            Draw_Pixel((xc + a), (yc + b), colour);
            Draw_Pixel((xc + b), (yc + a), colour);
            Draw_Pixel((xc - a), (yc + b), colour);
            Draw_Pixel((xc - b), (yc + a), colour);
            Draw_Pixel((xc + b), (yc - a), colour);
            Draw_Pixel((xc + a), (yc - b), colour);
            Draw_Pixel((xc - a), (yc - b), colour);
            Draw_Pixel((xc - b), (yc - a), colour);
        }

        if(p < 0)
        {
            p += (0x03 + (0x02 * a++));
        }
        else
        {
            p += (0x05 + (0x02 * ((a++) - (b--))));
        }
    }while(a <= b);
}


void Draw_V_Line(signed int x1, signed int y1, signed int y2, unsigned colour)
{
    signed int pos = 0;
    signed int temp = 0;

    if(y1 > y2)
    {
       swap(&y1, &y2);
    }

    while(y2 > (y1 - 1))
    {
        Draw_Pixel(x1, y2, colour);
        y2--;
    }
}


void Draw_H_Line(signed int x1, signed int x2, signed int y1, unsigned colour)
{
    signed int pos = 0;
    signed int temp = 0;

    if(x1 > x2)
    {
       swap(&x1, &x2);
    }

    while(x2 > (x1 - 1))
    {
        Draw_Pixel(x2, y1, colour);
        x2--;
    }
}


void Draw_Triangle(signed int x1, signed int y1, signed int x2, signed int y2, signed int x3, signed int y3, unsigned char fill, unsigned int colour)
{
    signed int a = 0;
    signed int b = 0;
    signed int sa = 0;
    signed int sb = 0;
    signed int yp = 0;
    signed int last = 0;
    signed int dx12 = 0;
    signed int dx23 = 0;
    signed int dx13 = 0;
    signed int dy12 = 0;
    signed int dy23 = 0;
    signed int dy13 = 0;

    switch(fill)
    {
        case YES:
        {
            if(y1 > y2)
            {
                swap(&y1, &y2);
                swap(&x1, &x2);
            }
            if(y2 > y3)
            {
                swap(&y3, &y2);
                swap(&x3, &x2);
            }
            if(y1 > y2)
            {
                swap(&y1, &y2);
                swap(&x1, &x2);
            }

            if(y1 == y3)
            {
                a = b = x1;

                if(x2 < a)
                {
                    a = x2;
                }
                else if(x2 > b)
                {
                    b = x2;
                }
                if(x2 < a)
                {
                    a = x3;
                }
                else if(x3 > b)
                {
                    b = x3;
                }

                Draw_H_Line(a, (a + (b - (a + 1))), y1, colour);
                return;
            }

            dx12 = (x2 - x1);
            dy12 = (y2 - y1);
            dx13 = (x3 - x1);
            dy13 = (y3 - y1);
            dx23 = (x3 - x2);
            dy23 = (y3 - y2);
            sa = 0,
            sb = 0;

            if(y2 == y3)
            {
                last = y2;
            }
            else
            {
                last = (y2 - 1);
            }

            for(yp = y1; yp <= last; yp++)
            {
                a = (x1 + (sa / dy12));
                b = (x1 + (sb / dy13));
                sa += dx12;
                sb += dx13;
                if(a > b)
                {
                    swap(&a, &b);
                }
                Draw_H_Line(a, (a + (b - (a + 1))), yp, colour);
            }

            sa = (dx23 * (yp - y2));
            sb = (dx13 * (yp - y1));
            for(; yp <= y3; yp++)
            {
                a = (x2 + (sa / dy23));
                b = (x1 + (sb / dy13));
                sa += dx23;
                sb += dx13;

                if(a > b)
                {
                    swap(&a, &b);
                }
                Draw_H_Line(a, (a + (b - (a + 1))), yp, colour);
            }


            break;
        }
        default:
        {
            Draw_Line(x1, y1, x2, y2, colour);
            Draw_Line(x2, y2, x3, y3, colour);
            Draw_Line(x3, y3, x1, y1, colour);
            break;
        }
    }
}


void Draw_Font_Pixel(signed int x_pos, signed int y_pos, unsigned int colour, unsigned char pixel_size)
{
     unsigned char i = 0x00;

     ST7735_Set_Addr_Window(x_pos, y_pos, (x_pos + pixel_size - 1), (y_pos + pixel_size - 1));

     for(i = 0x00; i < (pixel_size * pixel_size); i++)
     {
         ST7735_Word_Write(colour);
     }
}


void print_char(signed int x_pos, signed int  y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, char ch)
{
     unsigned char i = 0x00;
     unsigned char j = 0x00;

     char value = 0x00;

     if(font_size < 0)
     {
         font_size = 1;
     }

     if(x_pos < font_size)
     {
         x_pos = font_size;
     }

     for (i = 0x00; i < 0x05; i++)
     {
         for (j = 0x00; j < 0x08; j++)
         {
             value = 0x00;
             value = ((font[((unsigned char)ch) - 0x20][i]));

             if((value >> j)  & 0x01)
             {
                 Draw_Font_Pixel(x_pos, y_pos, colour, font_size);
             }
             else
             {
                 Draw_Font_Pixel(x_pos, y_pos, back_colour, font_size);
             }

             y_pos = y_pos + font_size;
          }
          y_pos -= (font_size << 0x03);
          x_pos += font_size;
      }

      x_pos += font_size;

      if(x_pos > width)
      {
          x_pos = (font_size + 0x01);
          y_pos += (font_size << 0x03);
      }
}


void print_str(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, char *ch)
{
     do
     {
         print_char(x_pos, y_pos, font_size, colour, back_colour, *ch++);
         x_pos += (font_size * 0x06);
     }while((*ch >= 0x20) && (*ch <= 0x7F) && (*ch != '\n'));
}


void print_C(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value)
{
     char ch[4] = {0x20, 0x20, 0x20, 0x20};

     if(value < 0x00)
     {
        ch[0] = 0x2D;
        value = -value;
     }
     else
     {
        ch[0] = 0x20;
     }

     if((value > 99) && (value <= 999))
     {
         ch[1] = ((value / 100) + 0x30);
         ch[2] = (((value % 100) / 10) + 0x30);
         ch[3] = ((value % 10) + 0x30);
     }
     else if((value > 9) && (value <= 99))
     {
         ch[1] = (((value % 100) / 10) + 0x30);
         ch[2] = ((value % 10) + 0x30);
         ch[3] = 0x20;
     }
     else if((value >= 0) && (value <= 9))
     {
         ch[1] = ((value % 10) + 0x30);
         ch[2] = 0x20;
         ch[3] = 0x20;
     }

     print_str(x_pos, y_pos, font_size, colour, back_colour, ch);
}


void print_I(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value)
{
    char ch[6] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20};

    if(value < 0)
    {
        ch[0] = 0x2D;
        value = -value;
    }
    else
    {
        ch[0] = 0x20;
    }

    if(value > 9999)
    {
        ch[1] = ((value / 10000) + 0x30);
        ch[2] = (((value % 10000) / 1000) + 0x30);
        ch[3] = (((value % 1000) / 100) + 0x30);
        ch[4] = (((value % 100) / 10) + 0x30);
        ch[5] = ((value % 10) + 0x30);
    }

    else if((value > 999) && (value <= 9999))
    {
        ch[1] = (((value % 10000) / 1000) + 0x30);
        ch[2] = (((value % 1000) / 100) + 0x30);
        ch[3] = (((value % 100) / 10) + 0x30);
        ch[4] = ((value % 10) + 0x30);
        ch[5] = 0x20;
    }
    else if((value > 99) && (value <= 999))
    {
        ch[1] = (((value % 1000) / 100) + 0x30);
        ch[2] = (((value % 100) / 10) + 0x30);
        ch[3] = ((value % 10) + 0x30);
        ch[4] = 0x20;
        ch[5] = 0x20;
    }
    else if((value > 9) && (value <= 99))
    {
        ch[1] = (((value % 100) / 10) + 0x30);
        ch[2] = ((value % 10) + 0x30);
        ch[3] = 0x20;
        ch[4] = 0x20;
        ch[5] = 0x20;
    }
    else
    {
        ch[1] = ((value % 10) + 0x30);
        ch[2] = 0x20;
        ch[3] = 0x20;
        ch[4] = 0x20;
        ch[5] = 0x20;
    }

    print_str(x_pos, y_pos, font_size, colour, back_colour, ch);
}


void print_D(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, unsigned int value, unsigned char points)
{
    char ch[5] = {0x2E, 0x20, 0x20, 0x20, 0x20};

    ch[1] = ((value / 1000) + 0x30);

    if(points > 1)
    {
        ch[2] = (((value % 1000) / 100) + 0x30);

        if(points > 2)
        {
            ch[3] = (((value % 100) / 10) + 0x30);

            if(points > 3)
            {
                ch[4] = ((value % 10) + 0x30);
            }
        }
    }

    print_str(x_pos, y_pos, font_size, colour, back_colour, ch);
}


void print_F(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, float value, unsigned char points)
{
    signed long tmp = 0x0000;

    tmp = value;
    print_I(x_pos, y_pos, font_size, colour, back_colour, tmp);
    tmp = ((value - tmp) * 10000);

    if(tmp < 0)
    {
       tmp = -tmp;
    }

    if((value >= 9999) && (value < 99999))
    {
        print_D((x_pos + (0x24 * font_size)), y_pos, font_size, colour, back_colour, tmp, points);
    }
    else if((value >= 999) && (value < 9999))
    {
        print_D((x_pos + (0x1E * font_size)), y_pos, font_size, colour, back_colour, tmp, points);
    }
    else if((value >= 99) && (value < 999))
    {
        print_D((x_pos + (0x18 * font_size)), y_pos, font_size, colour, back_colour, tmp, points);
    }
    else if((value >= 9) && (value < 99))
    {
        print_D((x_pos + (0x12 * font_size)), y_pos, font_size, colour, back_colour, tmp, points);
    }
    else if(value < 9)
    {
        print_D((x_pos + (0x0C * font_size)), y_pos, font_size, colour, back_colour, tmp, points);

        if(value < 0)
        {
            print_char(x_pos, y_pos, font_size, colour, back_colour, 0x2D);
        }
        else
        {
            print_char(x_pos, y_pos, font_size, colour, back_colour, 0x20);
        }
    }
}

 

main.c

#include "STM8S.h"
#include "ST7735.h"


unsigned int width;
unsigned int length;


void setup_clock(void);
void setup_GPIOs(void);


void main(void)
{
     float f = -0.09;
     signed int i = -9;
     signed char c = 127;

     setup_clock();
     setup_GPIOs();
     ST7735_init();

     ST7735_Set_Rotation(0x01);

     TFT_fill(Swap_Colour(GREEN));
     Draw_Circle(79, 63, 20, YES, Swap_Colour(RED));
     delay_ms(4000);

     TFT_fill(Swap_Colour(WHITE));

     Draw_Circle(6, 6, 4, YES, RED);
     Draw_Circle(153, 6, 4, YES, RED);
     Draw_Circle(6, 121, 4, YES, RED);
     Draw_Circle(153, 121, 4, YES, RED);

     delay_ms(1000);

     Draw_Line(14, 0, 14, 127, CYAN);
     Draw_Line(145, 0, 145, 127, CYAN);
     Draw_Line(0, 14, 159, 14, CYAN);
     Draw_Line(0, 113, 159, 113, CYAN);

     delay_ms(1000);

     Draw_Rectangle(17, 17, 142, 110, YES, ROUND, BLUE, WHITE);
     delay_ms(1000);

     print_str(22, 58, 2, YELLOW, BLUE, "MicroArena");
     delay_ms(4000);

     TFT_fill(BLACK);
     print_str(20, 90, 1, YELLOW, BLACK, "www.fb.com/MicroArena");

     while(1)
     {
             print_F(60, 20, 1, BLUE, BLACK, f, 2);
             print_C(60, 40, 1, RED, BLACK, c);
             print_I(60, 60, 1, GREEN, BLACK, i);
             f += 0.01;
             c -= 1;
             i += 1;
             if(c < -128)
             {
                 c = 127;
             }
             delay_ms(60);
     };
}


void setup_clock(void)
{
       CLK_DeInit();

       CLK_HSECmd(ENABLE);
       CLK_LSICmd(DISABLE);
       CLK_HSICmd(ENABLE);
       while(CLK_GetFlagStatus(CLK_FLAG_HSERDY) == FALSE);

       CLK_ClockSwitchCmd(ENABLE);
       CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
       CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);

       CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE,
       DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);

       CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART2, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER3, DISABLE);
       CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE);
}


void setup_GPIOs(void)
{
       GPIO_DeInit(SPI_PORT);
       GPIO_DeInit(CTL_PORT);
}

 

 

Explanation

Well that’s a hell lot code. Explaining the working of the ST7735 TFT display is beyond the scope of this article. The goal here is just the integration of such displays with STM8s. The library I coded here has several functions which however need some explanation.

The following functions set display inversion and orientation.

void ST7735_Invert_Display(unsigned char i);
void ST7735_Set_Rotation(unsigned char m);

For graphics, the following functions can be used:

/* 
Fills the entire TFT area with the designated colour.
*/
 
void TFT_fill(unsigned int colour);

 

/*
Draws a pixel of designated colour on coordinate (x_pos, y_pos).
*/

 

void Draw_Pixel(signed int x_pos, signed int y_pos, unsigned int colour);

 

/*
Draws a line of designated colour from point (x1, y1) to (x2, y2).
*/

 

void Draw_Line(signed int x1, signed int y1, signed int x2, signed int y2, unsigned int colour);

 


/*
Draws a rectangle from point (x1, y1) to (x2, y2). “Fill” states whether or not the rectangular area is solid filled. “Type” states whether the edges of the rectangle are round or square. “Colour” states the colour of the edges of the rectangle and “back colour” states the colour of the area inside the rectangle.
*/

 

void Draw_Rectangle(signed int x1, signed int y1, signed int x2, signed int y2, unsigned char fill, unsigned char type, unsigned int colour, unsigned int back_colour);

 

/*
Draws a circle of a given radius with center at (xc, yc). Argument “radius” states radius of the circle in pixels. “Fill” states whether or not the circular area is solid filled. “Colour” states colour of the circle.
*/

 


void Draw_Circle(signed int xc, signed int yc, signed int radius, unsigned char fill, unsigned int colour);

 

/*
Draws a vertical line of designated colour from point (x1, y1) to point (x1, y2)
*/

 

void Draw_V_Line(signed int x1, signed int y1, signed int y2, unsigned colour);

 

/*
Draws a horizontal line of designated colour from point (x1, y1) to point (x2, y1)
*/

 

void Draw_H_Line(signed int x1, signed int x2, signed int y1, unsigned colour);

 

/*
Draws a triangle of designated colour in the area enclosed by points (x1, y1), (x2, y2) and (x3, y3). “Fill” states whether or not the occupied area is solid filled.
*/

 

void Draw_Triangle(signed int x1, signed int y1, signed int x2, signed int y2, signed int x3, signed int y3, unsigned char fill, unsigned int colour);

 

For printing texts, the following functions can be used:

/*
Prints a single character “ch” at (x_pos, y_pos) with size stated by “font_size”. “Colour” states font colour and “back_colour” states the font background colour.
*/
 
void print_char(signed int x_pos, signed int  y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, char ch);

 

/*
Prints a string of characters from point (x_pos, y_pos) with size stated by “font_size”. “Colour” states font colour and “back_colour” states the font background colour.
*/

 

void print_str(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, char *ch);

 

/*
Prints a character type variable in “value” at (x_pos, y_pos) with size stated by “font_size”. “Colour” states font colour and “back_colour” states the font background colour.
*/

 

void print_C(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value);
 
/*
Prints an integer type variable in “value” at (x_pos, y_pos) with size stated by “font_size”. “Colour” states font colour and “back_colour” states the font background colour.
*/
 
void print_I(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, signed int value);

 

/*
Prints a float type variable in “value” at (x_pos, y_pos) with size stated by “font_size”. “Colour” states font colour and “back_colour” states the font background colour. Points states the number of digits after decimal point.
*/

 

void print_F(signed int x_pos, signed int y_pos, unsigned char font_size, unsigned int colour, unsigned int back_colour, float value, unsigned char points);

Initialize the TFT display before using it by including the following initialization function in the main file:

ST7735_init();

Since the TFT display communicates by using SPI communication method, enable the SPI peripheral clock and necessary GPIOs:

CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);

Font.h contains the character fonts and must be included to print texts, symbols and numbers.

One word of caution, by the way, is to look out for possible stack overflow and memory model related issues. If such a case arise then you should check the memory model of your code from project settings as shown:

Stack

Usually this case occurs when we try to declare a large array or do something similar. By default, short stack memory model is selected and most projects will flawlessly work with this memory model. However, for some projects especially those related to TFT, OLED, graphical displays, GSM, GPS and similar, long stack model is a must or else you won’t be able to compile your code any way.

Demo

 

TFT (1) TFT (2) TFT (3)

Continue Reading ...

Related Posts

2 comments

  • Hi SHAWON SHAHRYIAR

    I am wondering how to get a Max31855 to talk to a STM8s via SPI.

    JP

    • What’s to wonder about it? It is a simple SPI communication and SPI for STM8 is no different from the SPI of other MCUs…. The following lines are taken from the device’s datasheet and the write up there states how to communicate with it:

      “Drive CS low to output the first bit on the SO pin. A complete serial-interface read of the cold-junction compensated thermocouple temperature requires 14 clock cycles. Thirty-two clock cycles are required to read both the thermocouple and reference junction temperatures (Table 2 and Table 3.) The first bit, D31, is the thermocouple temperature sign bit, and is presented to the SO pin within tDV of the falling edge of CS. Bits D[30:18] contain the converted temperature in the order of MSB to LSB, and are presented to the SO pin within tD0 of the falling edge of SCK. Bit D16 is normally low and goes high when the thermocouple input is open or shorted to GND or VCC. The reference junction temperature data begins with D15. CS can be taken high at any point while clocking out con-version data. If T+ and T- are unconnected, the thermocouple temperature sign bit (D31) is 0, and the remainder of the thermocouple temperature value (D[30:18]) is 1.”

Leave a Reply

Your email address will not be published. Required fields are marked *