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