Browse the source code for my STM8 libraries as individual files.


Download all the library source code, with headers and Makefile.

Current version: October 10, 2018

Browse or Clone all the library source code from Github.



Header files

For convenience, I have one header file that brings in the right header files based on whether STM8103 or STM8105 is defined. Also, many of the libraries need to know the CPU type. For example, the -103 uses UART1 and the -105 uses UART2.

To compile for the stm8s103 CPU, use something like this in your Makefile:
SDCC = sdcc -mstm8 -DSTM8103

And your C source code will have this in your #include area:
#include "stm8s_header.h"

stm8s_header.h: loads the CPU header files and vectors.h
stm8_103.h: Defines for the stm8s103 CPU
stm8_105.h: Defines for the stm8s105 CPU
vectors.h: Defines for the interrupt vectors

Here are the header files for the inline assembly:
stm8_103.inc: Defines for the stm8s103 CPU
stm8_105.inc: Defines for the stm8s105 CPU

Library for a system clock

This library uses TIMER4 and provides millisecond and 1/10 second callbacks. It has functions to get and set the clock in binary or as a string. The millisecond callback is very handy for polling keypads and the 1/10 second callback is useful for keeping various timers and counters. More info at the above link.

Library for the MAX7219 LED driver chip and modules

The MAX7219 display driver chip can handle 64 LED segments or dots. It has its own memory and handles the segment/dot multiplexing. On eBay, this appears as an 8 digit 7-segment module or an 8x8 LED matrix. It is easy to connect many together to form larger displays.

Initialize your modules with m7219_init() with the display type and driver chip count. Then feed ASCII characters or strings with m7219_putc() and m7219_puts(). Move the current position with m7219_curs(). Set the overall brightness with m7219_bright(). With a 7-segment display, insert an ASCII decimal point after any character in a string and it will show correctly. Or if sending characters with m7219_putc(), set the bit-7 for the decimal point.

The example program is set to use either 3 7-segment (8 digit) modules in a string, or two 4-device modules connected (making an 8x64 dot display). The dot matrix display shows a moving marquee or a simulated clock. The 7-segment displays show a simulated clock on #1, various words on #2, and a running counter on #3. Note that the example program uses my other library lib_bindec and the STM8103 define files, which you can download with the link above.

lib_max7219.c Code here.
lib_max7219.h Header file.
lib_max7219.font Font file.
test_max7219.c Example/test program.


TODO: Since the dot matrix displays use so many individual LEDs for every character, it would be nice to get more efficient use by using a variable width font or on-the-fly kerning.

Library for the TM1638 boards

The TM1638 is a controller for both an 8-digit LED display and a keypad. There are inexpensive boards with 8 and 16 keys. More info at the above link.

Library for PWM and servo control

This library controls 1, 2, or 3 output channels for power control (ordinary PWM) or to control servo(s). More info at the above link.

AES Encode and Decode Library

I wanted to get the best performance for these functions, so I used lookup tables and a lot of inline assembly. This makes the size almost 4K. I could save at least 1.5K by trading six lookup tables for CPU time. Note that SDCC and Cosmic C use different calling conventions, so there are a number of conditionals around the function parameters.

aes_stm8.c Code here.
aes_stm8.h Header file.
aes_tables.h Six lookup tables, generated by aes_tables.c.

The encode and decode SBOX tables came from the FIPS-197 document.

16-bit and 32-bit binary to decimal functions

These are lightweight but fast functions I wrote with inline assembly. They can be handy when you want to display numbers, but don't need all the features of printf(). This also has a tiny 8-bit binary to ASCII hex function.

lib_bindec.c Code here.
lib_bindec.h Header file.

I find it interesting that STM8 does not have the DAA instruction, but it does have two nifty divide instructions. That makes the 16-bit conversion very easy. If you are wondering about the 32-bit code, I found that it was better to do the DAA _before_ multiplying by two, in the left shifts following. Since the correction is no longer the usual 0x06 or 0x60, but only half that, the DAA cannot cause carry or half-carry and is safe for the left shifts. The 32-bit conversion does eat a lot of cycles, but "if you need it, you need it." I thought about also having a 24-bit version, but those extra eight loops probably won't add up to much in the big picture.

LCD Library for displays using the Hitachi HD44780 (or equivalent)

As I mentioned in the previous page, the HD44780 driver is very common with small LCD modules, so this code can probably work with most of them. This works with every LCD I have bought off ebay, from 2x16 to 4x20. To save output pins, I use the 4-bit data mode and just assume that 500 microseconds is enough for a data write operation. The STM8S103 has pins C4 to C7 conveniently available, so I chose those for the data lines. I hate convoluting data lines. C3 is the RS (command vs. data) and is very easy to set or clear when writing a command or data.

lib_lcd.c Code here.
lib_lcd.h Header file.


Library for matrix keypad

Here is my library for using generic keypads on STM8. It can handle any number of rows and columns and you can use any pins you wish. Note that if you use "true open drain" pins, you will need to add a pull-up resistor.

Matrix keypad library

ALPS Rotary encoder

If you are not familiar with a rotary encoder, it is a rotary switch with two active pins. When you rotate it, the pins change voltage and your software can keep track of how many clicks it has been rotated. Like many (or most?) encoders, this one just starts wherever it was left from last time. If you need a rotary switch that gives its absolute location, look for one that has BCD or Gray code outputs.

I have used rotary encoders with pins set to Interrupt-On-Change, but I was not happy with so many useless interrupts triggered by switch bounce. Polling every 1 to 4 milliseconds seems to work just fine.

lib_rotary.c Code here.
lib_rotary.h Header file.

As mentioned in the other page, you can find this rotary switch HERE.

STM8 UART

The UART is pretty easy to use, but there are a lot of options and it might be easy to miss some detail. For instance, I spent an hour (it seemed) with my oscilloscope watching bits sent at the wrong baud rate. Turns out I did not notice a note in the manual that BRR2 must be written before BRR1. Problem solved. Moral of the story: It's better to put good code in a library and forget about it.

This library uses either UART1 or UART2, depending on whether you are compiling for the -103 or -105 CPU. It expects that the -103 uses the 16mhz internal oscillator and the -105 uses the 8mhz crystal.

The default RX and TX buffer sizes are 16 each, but you can change these in lib_uart.h For example, if your input is a command line interface, you might reduce the RX size to 4. If you output long lines and don't want to wait for the TX buffer to empty, you might increase the TX buffer to 64.

lib_uart.c Code here.
lib_uart.h Header file.


Pulse capture on Timer2

This is a pretty simple library for capturing pulses with timer2. The test program shows how you could use bit capture to convert pulses into serial bits. The test program also uses the binary and UART libs. You can choose a clock prescaler for maximum pulse widths from 4 milliseconds to 65 seconds. Obviously, you trade precision for duration, but you have a choice.

lib_cap2.c Code here.
lib_cap2.h Header file.
test_cap2.c Test program.


Other libraries not yet documented here:

lib_adc: Get value from an analog pin.
lib_cli: Implement a command line interface.
lib_eeprom: EEPROM unlock and lock functions.
lib_i2c: I2C primitives.
lib_log: Keep a system log in EEPROM or Flash memory.
lib_m9800: Get temperature from Microchip 9800 chip.

But these are documented on my Github Wiki pages

Goals and philosophy:

My goal with these libraries is to get the smallest and fastest code for the STM8 CPU family. They are lightweight so that even the stm8s103 with only 8K of Flash can do very useful things. I use inline assembly when the compiler output looks bloated, or I want to get the device timings correct.

My philosophy is that main program code SHOULD NOT use inline assembly. It would be harder to maintain, even for the original author. Main program code should be maintainable by anybody. Library code, however, will be left alone after debugging. It will be used by many projects, and any improvements in size or speed will echo through every project that uses it. So libary code MAY use inline assembly in carefully selected parts. In some cases, the size savings can be great. Ten bytes here, twenty there, multiplied by the number of libraries used in a project can make it worthwhile. An extreme example is my AES-128 encryption/decryption code. It would be hideously larger and slower without inline assembly.

I want the libraries to be easy to use. Just add #include "lib_xxxx.h" and don't worry about interrupts. Initialization is with a function called xxxx_init(). Options are described in the .h file. Generally, configuration settings go in the .h file so that the C source file avoids changes if possible.

I use both the stm8s103 and stm8s105 chips, so I have a main libs/ directory with -DSTM8103 to compile for the -103. And I have a separate libs_105/ directory full of symlinks to the main libs/ directory and they compile with -DSTM8105. It works for me.

Questions or comments? Feel free to contact me:
richard@hodges.org

I am currently available for software development projects.

This web page made with vi.
I write good code, not fancy HTML.

Last page update: December 21, 2018