Starting STM8 Microcontrollers

STM8S003K3 Discovery

Some Useful Tips

When using a new compiler, I evaluate some certain things. For instance, how do I include my own written library files, interrupt management, what conventions I must follow and what dos and don’ts must be observed.

Creation & Addition of libraries

At some point in working with any microcontroller, you’ll need two basic libraries more than anything else. These are LCD and delay libraries. LCDs are great tools for quickly projecting or presenting data apart from debugging a code with a debugger. Similarly, time-wasting delay loops help us slow down things at our liking. Humans are not as fast as machines. Delays can be avoided in many novel ways but delays keep things simple and so are necessities in some areas.

The Standard Peripheral Library only provides libraries for hardware peripherals and surely not for anything else. It is also practically impossible to provide library for all hardware on available on the planet. Thus, whenever when we will be needing new hardware integrations with STM8s, we will have to code and tag our libraries with our projects. So how can we do so?

Earlier in this article I discussed about alphanumeric LCDs and delays. If you check the datasheet of such LCDs, you’ll find initialization sequences in some while in others you may also find ready-made codes. These sequences are needed to be translated in code just like what we do with I2C or SPI-based devices.  Shown below is such an example:

LCD Sequence

Creating new libraries is simple. Just need to follow the following steps:

  • There should be a header file and a source file for every new module. For example, h and lcd.c.
  • Every header file should start with the inclusion of h header file (#include “stm8s.h”). This header is needed because it allows the access to the internal hardware modules available in a STM8 micro. For example, we will need access to GPIOs to develop our LCD library.
  • A good practice is that the header files only contain function prototypes, definitions, constants, enumerations and global variables.
  • The corresponding source file must only include its header file in beginning.
  • The source file should contain the body of codes for all functions declared in the header file.
  • When one library is dependent on the functions of another’s, the one that will be required in the new library must be included first. For example, we will need delay library in coding the LCD library because there are delay_ms functions in some parts of the library and so delay library should be included first. This should be the systematic order:
#include “stm8s_delay.h”
#include “lcd.h”

You can include these files at the bottom part of the stm8s_conf.h header file complying with right precedence as shown below:

File Inclusion

Alternatively, you can add them after the first line #include “stm8s.h” in your main source code.

 

Peripheral Clock Configurations

In most codes revealed so far, I made clock configurations every time. The reasons behind so are

  • Selection of right clock source.
  • Adjustment of peripheral and system clocks as per requirement. Again, it is mainly intended to balance off both power consumption and overall performance.
  • Disabling any unused hardware. This reduces power consumption and help us avoid certain hardware conflicts.

 

void clock_setup(void)
{
    CLK_DeInit();
                
    CLK_HSECmd(DISABLE);
    CLK_LSICmd(ENABLE);
    while(CLK_GetFlagStatus(CLK_FLAG_LSIRDY) == FALSE);
    CLK_HSICmd(ENABLE);
    while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);
                
    CLK_ClockSwitchCmd(ENABLE);
    CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
    CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
                
    CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, 
    DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);
                
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, ENABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
     CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE);
}

The following lines select clock sources:

CLK_DeInit();
                
CLK_HSECmd(DISABLE);
CLK_LSICmd(ENABLE);
while(CLK_GetFlagStatus(CLK_FLAG_LSIRDY) == FALSE);
CLK_HSICmd(ENABLE);
while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE);

What these lines do are enabling/disabling clock sources and wait for the sources to stabilize.

Then the following lines select clock prescalers and switching:

CLK_ClockSwitchCmd(ENABLE);
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
                
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, 
DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE);

Finally, the last segment enables/disables peripheral clocks:

CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);                
CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);          
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE); 

This segment is very important and should always be rechecked. Different chips have different internal hardware peripheral and so this segment will be different. For instance, STM8S105 has no UART1 module but it has UART2 instead. Research which hardware are available in your target micro and then code this segment. I ended up with several wasted hours of finding trouble in various cases only to find that I didn’t enable the required hardware.

Configuring Similar Stuffs Quickly

Sometimes you may end up doing the same stuff over and over again while you could have done it simply with one or two lines of code. For example, in the LCD library, the GPIOs that connect with the LCD share the same configurations. All are fast push-pull outputs.

 GPIO_Init(LCD_PORT, LCD_RS, GPIO_MODE_OUT_PP_HIGH_FAST);
 GPIO_Init(LCD_PORT, LCD_EN, GPIO_MODE_OUT_PP_HIGH_FAST);
 GPIO_Init(LCD_PORT, LCD_DB4, GPIO_MODE_OUT_PP_HIGH_FAST);
 GPIO_Init(LCD_PORT, LCD_DB5, GPIO_MODE_OUT_PP_HIGH_FAST);
 GPIO_Init(LCD_PORT, LCD_DB6, GPIO_MODE_OUT_PP_HIGH_FAST);
 GPIO_Init(LCD_PORT, LCD_DB7, GPIO_MODE_OUT_PP_HIGH_FAST);

This can be done in a more simplistic manner with just one line of code:

GPIO_Init(LCD_PORT, ((GPIO_Pin_TypeDef)(LCD_RS | LCD_EN | LCD_DB4 | LCD_DB5 
                     | LCD_DB6 | LCD_DB7)), GPIO_MODE_OUT_PP_HIGH_FAST);

As you can see it is just a bunch of logical OR operation. The same method is applicable for other peripherals that share the same initialization function.

 

Some Stuffs About Cosmic C and SPL

  • Functions, variables and definitions in Cosmic C are case sensitive.
  • Functions with no arguments must not have empty argument areas. For example, you cannot write:
    void setup (); 

    You should write it as:

    void setup (void);
  • Definitions and constants can be declared as with any C compiler.
  • Wherever there are flags, you need to be careful. You should check and clear flags even if it is cleared by hardware. For instance, when reading ADC, the ADC End-Of-Conversion (EOC) flag is automatically cleared but still in the code you should check and clear it. ADC1_ClearFlag(ADC1_FLAG_EOC); Flags are so important that unless you check and clear them appropriately, you may not get the right result from your code. Personally, I didn’t care much until I got myself into trouble.
  • You can mix assembly codes with your C code to enhance performance and optimization. However, you need to have sound knowledge of the assembly instructions. This is a rare requirement. The delay library, for instance, uses no operation assembly instruction to achieve delays. This is written as shown:
    _asm ("nop"); 
  • Empty loops are ignored by the compiler as a part of code optimization.
  • Long ago, Atmel (now Microchip) published a document regarding ways to efficiently optimize C coding. This document holds true for most microcontrollers. For example, in that document it is stated that a decrementing do-while loop is much more faster and code efficient than an incrementing do-while You can apply the methods presented there and other similar tricks with STM8 microcontrollers too. The document can be found here:
    http://www.atmel.com/images/doc8453.pdf
  • Though I don’t feel it as a necessity and don’t recommend it, you can avoid using the SPL and still code by raw register level access. For example, you can blink a LED with the following code:
    #include "stm8s.h"
    
    
    void main (void)
    {
         GPIOD->DDR |= 0x01; 
         GPIOD->CR1 |= 0x01;
    
    
         for(;;) 
    
         {
             GPIOD->ODR ^= (1 << 0);
             delay_ms(100);
         };
    }
  • Don’t mess with configuration (fuse) bits unless needed. Most of the times you will never have to deal with them. AFRs are used when remapping is needed or to enable special GPIO functionality. These will be of most importance.
  • Bitwise and logic operations are useful. Not only they are fast, they just deal with the designated bits only. SPL has support for such operations but it is still better to know them. Here are some common operations:
#define bit_set(reg, bit_val)        reg |= (1 << bit_val)   
//For setting a bit of a register     

#define bit_clr(reg, bit_val)        reg &= (~(1 << bit_val))         
//For clearing a bit of a register

#define bit_tgl(reg, bit_val)        reg ^= (1 << bit_val)                   
//For toggling a bit of a register

#define get_bit(reg, bit_val)       (reg & (1 << bit_val))                   
//For extracting the bit state of a register

#define get_reg(reg, msk)           (reg & msk)                                 
//For extracting the states of masked bits of a register

 

Unlocking a Locked STM8 Chip

If you have accidentally locked a STM8 chip by setting the Readout Protection configuration bit and no longer able to use it, you can unlock it easily.

When you lock a chip, the programmer interface will give you a warning notification. If you retry to reprogram/erase a locked chip you’ll get an error like this:

LOCKED

No matter what you do, you won’t be able to use it.

To unlock, go to the light programmer interface of STVD and check the Unlock Device checkbox as shown below:

Unlock

Also select Erase before Programming radio button because it is highly likely that your target chip is not empty. Now once you retry to reprogram, it will get unlocked.

Mastering C Language

You need not to be a C whiz to work with microcontrollers but certain things will surely help you to resolve some critical problems with simple codes. You must check supported data types whenever you begin working in a new development environment and should always use unsigned-signed designations to avoid unnecessary mistakes. Likewise, variable size is also important. Pointer, structures, unions and arrays are helpful features of C-language. You must learn how to use and apply them successfully. Without these you can still work but things will look really dirty. When coding for a new work, you must try to settle what you wish from your system and how should it behave. There should be an organized workflow and thereby your code will automatically be formulated in a state-of-machine algorithm or as a real-time system. You must try to avoid delays and loops wherever possible. Try to avoid polling and use interrupt-based systems. This will make your device behave in real-time with zero latency. However, you must be careful in handling interrupts because interrupts within interrupts will cause your system to crash miserably. Functions make things modular and thus easy to modify or debug. Repeated tasks should be placed in functions. A blinking LED code may look simple and stupid but sometimes very useful for testing stuffs. Some basic knowledge on mathematics and algorithms are also requirements for becoming a good embedded-system specialist.

Epilogue

In the end, I would like to share that my tiny raw-level knowledge and experiences with STM32s (http://embedded-lab.com/blog/stm32-tutorials/) earlier paid off handsomely. Due to that I was able to compiler this article decently and quickly. Personally, I feel that whosoever knows STM8 micros well will master STM32s and vice-versa because except the cores all hardware in both architectures are not just similar but same sometimes. This is for the first time I have admired STM’s SPL. My experiences with STM32 SPL was not well as so I decided to go on my own. However, this time things were different. Things were joyful and less difficult.

I would like to thank a few people who influenced me in composing this article:

Though his methods are different than mine, his article guided me a lot in the beginning. It is perhaps the most popular site for tutorials on STM8s and well organized. He used STM8S105 Discovery.

His tutorials on STM8 are not based on SPL. He showed stuffs with raw-level register access and with IAR compiler. Still his blog is informative.

  • http://www.emcu.it/. This Italian site was helpful in getting some early info.
  • STMicroelectronics team for releasing the STM8CubeMX during my writeup.
  • Cosmic team for freeing up their C compiler.

 

I spent nearly three months straight putting together all these things and at present, I must say that I have great expectations from STM8 microcontrollers.

 

 

A sequel of this post can be found here.

 

Happy coding.

Author: Shawon M. Shahryiar

https://www.facebook.com/groups/microarena

https://www.facebook.com/MicroArena                                                  24.04.2017

Related Posts

50 comments

  • Thanks for this article..
    I am looking for microsd card interface with STM8s discovery board. can you please provide the tutorial for microsd card?

  • In relation to disabling unused peripheral clocks as suggested by you:

    I found the following list of peripherals in the STM8S105 Discovery Board: Advanced control timer (TIM1), General-purpose timers (TIM2 and TIM3), Basic timer (TIM4), SPI, I2C, UART2, Window WDG, Independent WDG, ADC1,
    AWU timer, Beeper.

    Is this all?

    I could not find the clock peripheral configuration function for Window WDG, Independent WDG, Beeper in the Standard Peripheral Library.
    Is it not required?

    P.S. I am new to MCU programming with a little experience on Arduino. So please forgive me if the question is foolish.

    • 1. STM8S003K3 Discovery – the one I use for the blog is different from STM8S105…. They have different peripherals and so there will be differences in peripheral clocks…. Please check the device datasheet/STM8CubeMX for available hardware….

      2. WWDG and IWDG are set in option bytes and they don’t use peripheral/CPU clock…. Their oscillator is separate…. Due to these they don’t have clock configurations like other peripherals….

      P.S: No question is a noob question…. every question is allowed no matter how silly it may look….

  • Hi please someone tel me where can i find stm8s_delay.h and stm8s_delay.c
    Thanks

  • Hi , please someone tel me . Where can i find stm8s_delay.h and stm8s_delay.c
    Thanks ..

  • i am using stms003f3p6 controller..i have done as u told exactly but tim1 input capture is not displaying any value …according to your article it should display 10…i dont have any errors everything is fine…pulse on tim2 is ok ..it is coming as u said…but capture not working..please help me …thank you…

  • Hi Sir,
    i have just follwed your instruction provied in yout tutorial in main.c

    #include “stm8s.h”

    main()
    {
    while (1);
    }

    This error comes, can you please check why this error come, i am new and learn the controller programming.

    main.c:
    The command: “cxstm8 -i”d:\other datasheet\new folder\lib\stm8s_stdperiph_lib\libraries\stm8s_stdperiph_driver\inc” +debug -pxp -no -l +mods0 -pp -i”C:\Program Files (x86)\COSMIC\FSE_Compilers\CXSTM8\Hstm8″ -clDebug\ -coDebug\ main.c ” has failed, the returned value is: 1
    exit code=1.

    main.o – 2 error(s), 0 warning(s)

    Thanks,

  • Hi there, i solve the previous ADC problem. Anyway, u make some good tutorial on stm8 chips. Nice work

    • What was causing that issue? How did you solve it?

      • because i put all these

        ADC_DeInit(ADC1);
        ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_4Cycles);
        ADC_SchmittTriggerConfig(ADC1, ADC_Channel_7, DISABLE);
        ADC_ChannelCmd(ADC1, ADC_Channel_7, ENABLE);
        ADC_Init(ADC1, ADC_ConversionMode_Continuous, ADC_Resolution_12Bit, ADC_Prescaler_1);
        ADC_Cmd(ADC1, ENABLE);
        ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_None, ADC_ExtTRGSensitivity_All);

        in ‘while(1)’. It keeps looping.

        Once i put it before ‘while (1)’, it becomes normal.

  • Hi there, thanks for sharing. I learn alot thru your example, but I have encounter a problem with adc. Im currently using stm8l151k4t6. I wanna use the pin D7 as to read the voltage from my battery and monitor it (display on LCD). Can u please check where it goes wrong on my code?

    ADC_DeInit(ADC1);
    ADC_SamplingTimeConfig(ADC1, ADC_Group_SlowChannels, ADC_SamplingTime_4Cycles);
    ADC_SchmittTriggerConfig(ADC1, ADC_Channel_7, DISABLE);
    ADC_ChannelCmd(ADC1, ADC_Channel_7, ENABLE);
    ADC_Init(ADC1, ADC_ConversionMode_Continuous, ADC_Resolution_12Bit, ADC_Prescaler_1);
    ADC_Cmd(ADC1, ENABLE);
    ADC_ExternalTrigConfig(ADC1, ADC_ExtEventSelection_None, ADC_ExtTRGSensitivity_All);
    ADC_SoftwareStartConv(ADC1);
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    battery = ADC_GetConversionValue(ADC1);

  • hi shawon great tutorials it would be nice too if you covered the coide compiler for arm it’s a good free compiler

  • hi shawon thanks for your response and support it turns out that my problem was a license issue I stupidly thought i use one license on multiple pc’s I used the license for a particular computer for mine that’s why I’ve been having compilation issues you have to use the license file stm8 sends you that is generated by your own pc else it won’t compile it’ll jus kip throwing you errors

  • It seems that you didn’t follow my instructions completely…. I found some issues:

    1. You have included header and source files of ADC2, CAN, UART2, etc which are unavailable in STM8S103…. Add only files for the peripherals available in your target MCU…. Exclude the rest….

    2. You have not included stm8s_delay header and source files…. Either disable it from stm8s_conf.h header file if you are not going to use it or add both the header and the source files for it in your project….

    Resolve these and you are good to go….

    Thanks….

  • I haven’t compiled any of the examples yet I just tried to compile the main source file just for test purpose n it just keeps showing me the same errors

  • yes the comic compiler was installed properly i even received a license file from my mail with the instructions to copy the license file to the license folder in the install directory if you fail to do this it will keep popping up for you to put in the license file. iincluded all the source files and header files as instructed i am working with the cheap stm8s103f i uncommented the stm8s103f in the stm8.h header file as you instructed and just to compile the main file it just throws me errors

  • no I just followed your instructions I just compiled it after setup i did not write any code yet just compiled the default main file

    • Need more details….

      1. The version of STVD and Cosmic
      2. Which example is giving this issue?
      3. The chip you are using if it other than STM8S003
      4. Have you tried to compile something else other than my examples?
      5. Are the paths to libraries and other folders properly added?
      6. Is the Cosmic compiler registered properly?

  • it throws this line The command: “cxstm8 -iinc +debug -pxp -no -l +mods0 -pp -i”C:\Program Files (x86)\COSMIC\FSE_Compilers\Hstm8″ -clDebug\ -coDebug\ main.c ” has failed, the returned value is: 1
    exit code=1.

  • hi I’m having compilation issues when I compile it just throws me error about comic compiler located in the program file ialso excluded unwanted header files but my problems still weren’t solved

  • hi thanks for the tutorials but i am having compiler error issues even when I remove unnecessary header files it say comic compiler error

  • I am new to STM8S003k3 Discovery board.I have done UART communication using STM standard peripheral library example. Now I want to define any other GPIO pin for UART communication. Is it possible to use d0 and d1 pin for the UART communication? If yes, then please let me know how?

  • thank you very much for this article!

  • Thank you for your time and effort.

  • Good job bro

  • Thank you for this exceptionally comprehensive article, much appreciated

    Rando!

Leave a Reply

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