Continuing the STM8 Expedition
|
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.
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
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:
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
|
hi
i copied all the above (UART interrupt) code as directed (without any changing). only i added stm8s_delay.h.
but this error occurs
#error clnk Debug\mgstm_1007.lkf:86 Debug\stm8_interrupt_vector.o: symbol f_NonHandledInterrupt multiply defined (Debug\stm8s_it.o)
please guide
regards
Example with an encoder. The counter only counts up, regardless of the direction of rotation of the encoder. Where could be the problem?
Using the same pins or some other pin combinations? Encoder mode only works with certain pins only and so if you use some other pins this will happen.
How to fight trash data on ADC inputs? Even when I don’t connect any voltage source it shows some data.
Have the floating inputs grounded using 10k or suitable value resistors….
stm8
Hello, the interrupt handling is different from what the datasheet says. To clear the flag just read the SR and DR registers. In addition, if the 4 LSB of SR reports an error, there may not be an interruption, it is necessary to monitor these errors as well, and clean the register, as the datasheet says, I noticed this using an STM8S003F3, I don’t know if this happens with other models.
why are the lines
ADC1_ScanModeCmd(ENABLE);
ADC1_StartConversion();
written inside the while loop? Shouldn’t we set them once?
I’m using the scan mode + interrupt mode
I see. And what if we just use the interrupt handler function and not write anything inside the while loop?
I’m programming in IAR and just have noticed that the file stm8_interrupt_vector.c is missing. I found it under …\STM8S_StdPeriph_Lib\Project\STM8S_StdPeriph_Template\STVD\Cosmic and included it into my workspace. But during the making it gives out a bunch of errors. I could I solve this?
Didn’t use IAR and so can’t say why this is happening….
I figured out the answer: on IAR we activate the interruptions differently. We just enable the interrupts by calling enableInterrupts(); and in the interruption files we find out the corresponding interrupt handler function.
I enjoyed the tutorial. Thank you. Just one question: is it fine that my counter is incrementing in 2 instead of 1 while I turn the encoder?
Could be due to your encoder itself….
When I keep on turning the knob after the overflow value(1000) the counter becomes dizzy(it counts randomly). Is it a problem of the encoder? I use a scroll wheel encoder TTC.
it should not happens because it is weird…. I think it is an issue with the encoder….
Sir can i use this code for ILI9488 SPI TFT display of 320(RGB) x 480 Resolution?
No…. These TFT LCD chips and display resolutions are different….
Hello sir i am Chavda hiren
this timer is STVD is ok
But i Need This Timer a IAR IDE
Can you Plz Sir
void TIM2_setup(void)
{
TIM2_DeInit();
TIM2_TimeBaseInit(TIM2_PRESCALER_32, 1250);
TIM2_OC1Init(TIM2_OCMODE_PWM2, TIM2_OUTPUTSTATE_ENABLE, 1000,TIM2_OCPOLARITY_LOW);
TIM2_OC2Init(TIM2_OCMODE_PWM2, TIM2_OUTPUTSTATE_ENABLE, 1000, TIM2_OCPOLARITY_LOW);
TIM2_SetCompare1(100);
TIM2_SetCompare2(100);
TIM2_Cmd(ENABLE);
}
Thank you
IAR code will just be same as ST’s Standard Peripheral Library can also be used with it….
Shahryiar,
I am working with your code related to ST7735 TFT Display. When compiling COSMIC compiler is giving me an error for ST7735.c file and the error is as follows:
st7735.c:389(11) missing prototype
On line 389 of the ST7735.c is “swap(&y1, &y2);”
My question is where is the function defined for “swap”?
Thanks in advance
Adil
Seems like ST7735 header file is missing in your code…. swap function can be found in ST7735.c file….
Dear sir i have problem to use ram size of stm8s003k3
how can i use 1024 byte for serial received
please replay me i am waiting
Hi Shawon Shahryiar,
You mentioned this *”IAP can also be used for upgrading application firmware Over-The-Air (OTA)”* in this blog at the beginning, what does this mean?
And I know that STM32 is also not a wireless MCU but there are some solutions to upgrade firmware using ESP8266 and Bluetooth module through UART.
( https://www.st.com/en/embedded-software/stsw-stm8006.html ) I found this above source code as example of implementation of bootloader, please help me with this.
( https://www.st.com/en/embedded-software/stsw-stm8062.html ) and also this as a customised bootloader,
( https://community.st.com/s/case/5003W00000Eqj8TQAR/information-for-ota-feature-in-stm8s003fpf6 ). I raised a question in ST community about this and they told it is possible to use UBC(User Boot Code) area to update firmware. Please check and help me, may be it helps everyone.
Thanks
Junaid
1. Do wfi() and halt() have the same power savings?
2. If halt() is called, can the microcontroller still be woken up by an interrupt?
Hi Shawon
Thank you for these excellent tutorials.
I was just wondering why you use two output channels on TIM2? Do you connect them in parallel?
Hello all embedded people, my application is to read pwm on a pin for rise edge or fall edge (ANYEDGE) and produce a pwm signal with different duty cycle on another pin (without any button pressed).
Can anyone explain me how to use this example for my application? please help me 🙂
Thanks for useful tutorials
How can I store/initialize byte data into EEPROM at the time of programming?
Regards
can u help me with this ?
Gostei muito bom.
Hello Shawon,
Thank you for your great tutorials.
Could you please help me with NEC IR decoding using stm8s.
I want to use multichannel adc interrupt for eg (channel 2 ,3,4 of ADC1 ) but when i do this i got value from a single channel in all three buffer value. what i should do for correct data?? please suggest
hi again
an other problem! 🙁
i want to use multi channel “scan mode” only for 2 channel(CH2,CH3) and i used other adc pins for gpio purposes.
but… when adc runs and turns on, gpio pins become noisy!!!
whats problem?
thanks
hi shawon
i want to read “ADC1_GetBufferValue(0)” in timer interrupt… but it returns 0 !!!! (in the main.c it’s ok)
how can i do it?
First I want to say thank you for your useful tutorial.
then I have a question:
I need to store one byte data either on EEPROM or FLash memory. the problem is I need to write it into the memory every 5 minutes.
The datasheet says that the EEPROM can work for 100K cycles of erase/write, and that’s not enough for a long-time use of the device.
I want to know how many times (cycles) we can erase/write to an address on Flash memory.
thanks a lot
100k Cycles @ 5 min = 300 hours approximately. The device won’t last even a year. Better use battery-backed RAM or store your data in MCU’s SRAM and have it written to EEPROM/flash only at the event of a power failure.
Hi Shawon Shahryiar,
Thanks for all the useful tutorials.
Can you show an example of firmware update (Over-The-Air)OTA on stm8s?
Thanks in advance 🙂
STM8S is not a wireless MCU and neither it supports OTA implementation….
Hi Shawon Shahryiar,
You mentioned this *”IAP can also be used for upgrading application firmware Over-The-Air (OTA)”* in this blog at the beginning, what does this mean?
And I know that STM32 is also not a wireless MCU but there are some solutions to upgrade firmware using ESP8266 and Bluetooth module through UART.
( https://www.st.com/en/embedded-software/stsw-stm8006.html ) I found this above source code as example of implementation of bootloader, please help me with this.
( https://www.st.com/en/embedded-software/stsw-stm8062.html ) and also this as a customised bootloader,
( https://community.st.com/s/case/5003W00000Eqj8TQAR/information-for-ota-feature-in-stm8s003fpf6 ). I raised a question in ST community about this and they told it is possible to use UBC(User Boot Code) area to update firmware. Please check and help me, may be it helps everyone.
Thanks
Junaid
Hi
This is an excellent series of tutorial. I appreciate your efforts. I’m using the similar multi-channel ADC to read data from channel 3 and 7. But the problem that I have is, the ADC value doesn’t seem to update automatically, I need to reset it in order to get the updated data. Is there anything I’m missing in the ADC1 configuration that causes it? Thanks
Clear ADC flag….
Were you able to solve the error, i am facing a similar issue. The adc buffer seems to update only when the device is reset.
This code is very helpful, that you for showing it. There doesn’t seem to be a lot of documentation or resources for these processors, but their price makes them very attractive.
In my application, I use AIN2 and AIN3 since the pins for the other channels are required for other functionality. I am wondering if there is a way to just read those channels individually when I need to without having to scan channels 0-3 each time and without having to call a reconfiguration routine to switch between channels 2 and 3?
Hi. I’m using the STVD IDE with Cosmic with an STM8TL52F4 MCU with the ‘Minimize Code Size’ compiler option selected. Under Debug instrument->ICD MCU configuration->Options, I set the DATASIZE_bit6 Value to 1 (the other DATASIZE bits are 0) and made no other changes there. As I understand it, that should reserve a 1024 byte window near the end of EEPROM for my permanent (power-up to power-up) settings info starting at address 0x0800. I’m able to UNLOCK, write and read that area and LOCK it again without problems. However, with each debug session, I find that the area is always overwritten. How do I prevent that and keep that area secure? And I’m curious what it’s being overwritten WITH? I’m doing just as this demo suggests.
Hi Shawon. How to take more than one measurement with interrupt. Example AIN5 and AIN6 measurement with interrupt ?
I use Eclipse & sdcc .
void timer1_CAP_isr (void) __interrupt (12) {
I have the following error.
Unused declaration of function ‘timer1_CAP_isr’
But the interruption doesn’t work
The code is written with STVD and the compiler is Cosmic C. Surely it won’t work with other compilers but the concept would work. Thanks.
OK_TANKS.
Hi Sharon,
Is the delay necessary for the programming action?
I used roughly the same method(but I did not add a delay but only a EOP flag check) and did a action check after programming it works fine at start but as soon as I restart the thing and the code reads old data from the same eeprom address like the programming action never occurred.
Shawon,
Your inspirational blog has gotten me started with STM32 and STM8s micros. You have done a marvelous job in explaining each aspect of the hardware in each of these micros and the example code is well written. Thank you so much for taking the time to put this together for all to use.
Thank you,
Adil Khan
🙂
Hello… Can you suggest me an evaluation kit/development kit for STM8S105S4T6C micro-controller? I need this controller for BLDC Motor control
Why not use this official discovery kit:
https://www.st.com/en/evaluation-tools/stm8s-discovery.html
The thing is the dev. kit you suggested is centered around the STM8S105C6T6 MCU. While my project strictly demands the use of STM8S105S4T6C MCU as the first priority or any MCU similar to it. Will the Discovery Kit MCU i.e. STM8S105C6T6 serve the purpose of my MCU? To be honest I’m quite new to micro-controllers and thus don’t know how to compare two MCUs i.e. I’m not being able to decide which aspects to consider while comparing two MCUs.
Hi Shawon Shahryiar,
I am using stm8s003f3 discovery board. In my project, I am using ADC1 multiple channels 0,1,2,3. In these four channels, I am using 0,1,3 as a normal ADC read and channel 2 as an interrupt based.
I am facing a problem that if configure ADC channel 0,1,3 and read value then ADC interrupts not occurred.
But if I comment multiple channels read then interrupt occurred.
Can you tell me why it is like that and can I read adc1 multi-channel with interrupt-based?
like
Channel0,1,3 read normal ADC from 3 potentiometers and only channel 2 as an interrupt based.
In my write up I stated “In scan mode, the ADC automatically scans a sequence of channels from channel 0 to channel n, keeping the results of AD conversion in data buffer registers. At the end of conversion, the results are ready to be read.” and so in your case it is not like 0 > 1 > 2 > 3…. 2 is missing in the scan sequence and so it will probably not work….
Hi Hi, Shawon Shahryiar,
Might be this is possible but my question is different.
My question is:- Can I use multichannel ADC with scan mode and ADC interrupt based at the same time with the diffrent channels?
Example:- Channel 0,1 as a scan mode and channel 2 as an ADC interrupt based simultaneously?
Hey i am also using same controller and using single ADC pin but adc value is fluctuating continuously without any input.can u please tell me why this is happening and what is the solution.
it must be floating….
Normally I don’t learn article on blogs, however
I wish to say that this write-up very pressured me to check out and do it!
Your writing taste has been surprised me. Thank you, very nice article.
🙂
Ϝirst ᧐f aⅼl I would ⅼike tօ say awesome blog!
Ι had а quick question tһɑt I’ɗ ⅼike to aѕk
іf yoᥙ don’t mind. Ӏ was curious to knoᴡ how you center yourself ɑnd clear yοur thoսghts prior to writing.
Ӏ’ѵе had difficulty clearing mү mind in getting mу ideas out tһere.
I tгuly do tɑke pleasure in writing howeᴠer
іt just ѕeems lіke tһe first 10 to 15 minutes tend to be lost simply ϳust trʏing to figure օut һow to begin. Any ideas or hints?
Kudos!
Well firstly, to me the concepts of all microcontrollers in world is same and so provided that you have some degree of knowledge of internal peripherals, you can unlock anyone of them by systematically trying out each peripheral on your own…. Secondly, how to start is up to you…. When I compose a blog and plan what I would be focusing on, I take things as such that my audience is in front of me and would likely to ask me the very basics…. I try to write things in simplest possible language and with minimum word count while highlighting what is most important…. A blog on any microcontroller should focus on every aspect and not just a few topics…. Lastly, planning and persistently going by the plan to achieve a vision will surely bring out a good result…. Just don’t lose focus and don’t let yourself be pressurized by too many unknown variables….
It’s not my first time to ѵisіt thіѕ web page, i am visiting this webѕite
dailly and obtain pleasɑnt information from herе
all the time.
I visited multiple blogs except tһe audio quality f᧐r audio songs existing аt this web paɡe iѕ tгuly superb.
Dear Shawon,
Thank you for your useful website and articles.
I have taken a look at ADC1_Init definition and I found it uses ADC1_ConversionConfig to set channels and conversion mode. So it seems using ADC1_Init once with all needed channels is enough. Am I right?
Thank you very much.
Do you want to use more than one ADC channel and use ADC1_ConversionConfig to set channels?
Hello,
I am learning stm8s, but i have a project in my mind, i am making Pong game with two encoders and PCD8544 LCD. Your tutorials are great and it’s very big source of knowledge for me, and i have a question about this article:
Is it possible to use two encoder this way? Or can it be done in the other way? I have stm8s103f3p6, and i know it has 4 interrupt pins, so I thought about using these for two encoders, but then i saw your article about QEI
TIM1 supports one QEI only since TI1 and TI2 are used for it…. TI3 and TI4 are not used for QEI…. Thus you can only use one encoder in the way I showed….
Hello Friend!!
Your stuff is great !!!
Would you have an example 433 mhz rf signal capture with flash code writing?
Ola amigo !!!
Seu material é excelente!
Você teria algum exemplo de captura de sinal rf 433 mhz com gravação na flash?
Hello friends, pleasant paragraph ɑnd good urging commented ɑt tһiѕ ρlace,
I ɑm truⅼy enjoying ƅy tһese.
Hi,
Thats great work
Do you have steps for to work ST7735 TFT IN 8 BIT 8080 mode
no…. I don’t have that…. I also don’t have ST7735 TFTs with 8080 interface for testing….
I don’t even understand how I ended up right here, however
I believed this publish used to be good. I don’t know who you are however definitely
you’re going to a well-known blogger should you aren’t already.
Cheers!
Many thanks…. 🙂
Thanks Shawon, your blogs are indeed very helpful. Keep Growing.
🙂
Hi Shawon Shahryiar, I follow your blogs and are verymuch helpful, can u guide me how to do an OTA firmware update?
Please 🙂 <3
Thank You.
why are you sending the received data back through TX pin?
To loop back and check easily what has been sent out and received….
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.”
Hi Shawon,
I have been using your tutorials to learn STM8’s, and the original post IO managed to find or down load as a pdf,
are the extension 2 and 3 available as a pdf too?
Andrew
Everything from the first to the last post can be found here: http://embedded-lab.com/blog/stm8-microcontrollers-final-chapters/10/