Compiler Comparison
RTOS Availability
STM8AF LED Timer
STM8AF Serial
STM8AF Benchmarks
STM8AL LED Timer
STM8AL Serial
The STMS001 is a rather new addition to ST's STM8 portfolio. At the time this tutorial was written, no STM8S001 evaluation boards were available commercially. Fortunately, an ST engineer has published a reference design, and sent me one boards (it is an early prototype with jumper wires soldered on the underside). The final version of the board has since become available via Rutronik.
The STM8S001 has only 8 pins, and multiple I/O functions are connected to each pin. There is no reset pin, and the SWIM pin is shared with other I/O. Thus the device can easily be bricked by enabling output on an I/O that shares the pin with SWIM early. While writing this tutorial, I made a mistake reading the datasheet, taking a value from a wrong line, accidentally enabling output on an I/O shared with SWIM. Since the STM8S001J3 wasn't easily available then, I had to wait a few weeks before I was able to get and solder a new one onto my board.
For this tutorial, I used a Debian GNU/Linux system, but the tutorial should work for other Linux distributions, MacOS, *BSD or other Unices.
The tools we use are
STM8S001J3 Reference design is connected to 5V power via the Mini-USB port. To write our program to the board, an ST-LINK/V2 is attached.
Depending on your operating system there might be an easy way to install SDCC 3.5.0 or newer using a package system or similar (e.g. apt-get install sdcc on Debian). While SDCC 3.4.0 should be sufficient for this tutorial, you might want to try a newer version in case you encounter any bugs. In particular, SDCC 3.4.0 has an issue with the library search path; this can be worked around by explicitly specifying the path to the standard library when linking.
SDCC binaries or a source tarball can be downloaded from its website.
The stm8flash source can be found at its GitHub location, where there is also a download link for a zip archive of the sources. To compile it, a C compiler, such as gcc, pkg-config and libusb need to be installed. Unzip the archive (e.g. using unzip stm8flash-master.zip) change into the directory stm8flash-master and type make
. In case there are any errors, such as header files not found, check that pkg-config and development files for libusb are installed.
We present a simple demo that increments a 3-bit LED counter once per second. This demonstrates setting up and using an accurate timer and doing basic I/O. Here is the C code:
// Source code under CC0 1.0 #include <stdint.h> #define CLK_CKDIVR (*(volatile uint8_t *)0x50c6) #define CLK_PCKENR1 (*(volatile uint8_t *)0x50c7) #define TIM1_CR1 (*(volatile uint8_t *)0x5250) #define TIM1_CNTRH (*(volatile uint8_t *)0x525e) #define TIM1_CNTRL (*(volatile uint8_t *)0x525f) #define TIM1_PSCRH (*(volatile uint8_t *)0x5260) #define TIM1_PSCRL (*(volatile uint8_t *)0x5261) #define PA_ODR (*(volatile uint8_t *)0x5000) #define PA_DDR (*(volatile uint8_t *)0x5002) #define PA_CR1 (*(volatile uint8_t *)0x5003) #define PB_ODR (*(volatile uint8_t *)0x5005) #define PB_DDR (*(volatile uint8_t *)0x5007) #define PB_CR1 (*(volatile uint8_t *)0x5008) #define PC_ODR (*(volatile uint8_t *)0x500a) #define PC_DDR (*(volatile uint8_t *)0x500c) #define PC_CR1 (*(volatile uint8_t *)0x500d) unsigned int clock(void) { unsigned char h = TIM1_CNTRH; unsigned char l = TIM1_CNTRL; return((unsigned int)(h) << 8 | l); } void main(void) { CLK_CKDIVR = 0x00; // Set the frequency to 16 MHz // Configure timer // 1000 ticks per second TIM1_PSCRH = 0x3e; TIM1_PSCRL = 0x80; // Enable timer TIM1_CR1 = 0x01; // Set ports for output PA_DDR = 0x08; PA_CR1 = 0x08; PB_DDR = 0x30; PB_CR1 = 0x30; PC_DDR = 0x38; // Bits 3, 4, 5 of port C. PC_CR1 = 0x38; // WARNING: SETTINGS BIT 6 OF PORT C OR BIT 1, 3 OR 5 of PORT D TO OUTPUT CAN BRICK STM8S001J3! for(;;) { uint8_t pa = 0x00, pb = 0x00, pc = 0x00; if((clock() / 1000) & 0x1) { pb |= 0x20; pa |= 0x08; } if(!((clock() / 1000) & 0x2)) // LED signal inverted vs. others. pb |= 0x10; if((clock() / 1000) & 0x4) { pc |= 0x38; } PA_ODR = pa; PB_ODR = pb; PC_ODR = pc; } }
SDCC is a freestanding, not a hosted implementation of C, and allows main to return void.
We set up the timer to increment once per millisecond, which allows us to implement a basic clock()
function. This function is used to control the increment of the LED counter.
The demo can be compiled simply by invoking SDCC using sdcc -mstm8 --std-c99 led.c
assuming the C code is in led.c. The option -mstm8
selects the target port (stm8). An .ihx file with a name corresponding to the source file will be generated.
Assuming stm8flash and led.ihx are in the same directory, the board is attached through an stlinkv2 device, ./stm8flash -c stlinkv2 -p stm8s001j3 -w led.ihx
will write the demo onto the board. It will run and count up to 7 on the LEDs 5, 4 and 3, then start again at 0.
The demo can be easily extended to a 5-bit counter that can count to 31 on all five LEDs (and closing JP9 after programming the device). However, one should be very careful to not enable output on bit 6 of port C and bits of 1, 3 and 5 of port D before the LED2 is to be switched on. By enabling output on bit 6 of port C and bits of 1, 3 and 5 of port D only 8 seconds after startup, the STM8S001 can still be reprogrammed using the ST-LINK/V2 in the first 8 seconds after applying power when JP9 is open. If bit 6 of port C or any bit of 1, 3 and 5 of port D is set to output at startup, the program will still work, but no other program can ever be written onto the STM8S001J3 again.
stm8flash was written by Valentin Dudouyt. It works both with stlink (including the one integrated on the discovery boards) and stlinkv2 devices. The programmer can be selected using -c stlink
or -c stlinkv2
. The target device is selected using the -p
option (to get a list of target devices, use the -p
option with an option argument that is not an stm8 device, e.g. -p help
. stm8flash will treat filenames ending in .ihx
or .hex
as Intel hex, and other filenames as binaries.
SDCC was initially written by Sandeep Dutta for the MCS-51, and has a relatively conservative architecture (see Sandeep Dutta, "Anatomy of a Compiler", 2000). It has been extended by various contributors and more recently, incorporated some cutting-edge technologies, in particular in register allocation (see Philipp Klaus Krause, "Optimal Register Allocation in Polynomial Time", 2013). The stm8 backend was mostly written by Philipp Klaus Krause for his research into bytewise register allocation and spilling (see Philipp Klaus Krause, "Bytewise Register Allocation", 2015).
SDCC is a C compiler that aims to be compliant with the C standards.
Important compiler options for STM8 developers include:
-c
to compile into object files to be linked later--std-c99
for compilation in C99 mode (some C99 features, e.g. variable-length arrays are not yet supported in sdcc though)--opt-code-size
for optimization for code size--max-allocs-per-node
to select the optimization level. the default value is 3000. Higher values result in more optimized code, longer compiler runtime, and higher memory usage during compilation.