Skip to content

Instructions for building SPL on Linux

Ken Yap edited this page Jan 29, 2020 · 8 revisions

How this page came about

I started programming for the STM8S103F3P6 blue breakout board using the SDCC toolchain and realised that I needed header files for the definitions as they did not come with SDCC. TG9541 very kindly pointed me to STM8S headers patched for SDCC which are derived from the ST Standard Peripherals Library (SPL), and explained the history behind it. It seems that ST's restrictive license had caused a lot of homebrew header files to be created for the STM8S. Eventually ST released the sources under a more liberal license, but the damage had already been done.

When I compiled my first program I realised that I had only the header files and still needed the library. Then followed a lot of false leads on the Internet. There are many outdated pages, talking about downloading the sources from ST, and patching, or pointing to an outdated release of SPL for Arch Linux. All these resources should be put out of their misery. So this page is to save you the runaround I had before finding the right way to build the SPL. Hopefully some day SDCC will be able to distribute the library and sources, saving a lot of work. Then this page can be retired too.

Why SPL?

Why use SPL? After all, the MCU resources are documented in the datasheet and all you have to do is access them as documented to do what you want. There are several reasons:

  • SPL is also used by other toolchains running on other platforms. Many of the programs you can find on the Internet use this library, so it's easier to adapt such programs, if allowed, modifying a little for SDCC syntax.
  • SPL header files use type checking and function prototypes for better error checking so it's harder to send the wrong kind of parameter to a function, e.g. swapping the arguments for port and pin.
  • The STM32 library API resembles the STM8 library API so it will be easier for you to port to that platform if you desire.

Steps

Choose a parent directory where you store source code packages, for example /usr/local/src.

Clone these Git repositories:

The first one needs no building. You can use the -I option to sdcc to add the include directory to the search path. I prefer to make a symbolic link in the project directory like this:

include -> /usr/local/src/stm8s-header/include

then you can just add -Iinclude to the sdcc options.

The library sources need to be built. The README suggests going into Project/STM8S_StdPeriph_test/SDCC and running make. You'll have to specify make spl.lib as the default target tries to make the test program and this doesn't compile, at least not with my SDCC.

Alternatively go to Libraries/STM8S_StdPeriph_Driver and run make DEVICE=STM8S103

If you are using SDCC 3.9 or later, you will need to edit Makefile and change the definition of AR from sdcclib to sdar, and the line:

$(AR) -a $(TARGET) $^

to

$(AR) -rc $(TARGET) $^

because sdcclib has been replaced by sdar. Now you should be able to build to get STM8S103/spl.lib

You can make a symlink to this from your project directory as with the include directory, or make a copy in the project directory. Then add spl.lib to the list of files given to the linking stage.

An example Makefile

Here is a Makefile which demonstrates how to specify the include directory and library file. The program is good old blink, of course.

CC=sdcc
CFLAGS=-mstm8
INCLUDES=-Iinclude
LIBS=spl.lib -lstm8

blink.ihx:      blink.rel
        $(CC) $(CFLAGS) $^ -o $@ $(LIBS)

%.rel:          %.c
        $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $(<:.c=.rel)

%.flash:        %.ihx
        stm8flash -cstlinkv2 -pstm8s103f3 -w$(<:.flash=.ihx)

clean:
        rm -f *.asm *.cdb *.lk *.lst *.map *.mem *.rel *.rst *.sym

Notice the pseudotarget %.flash. I can type make blink.flash and it will build if necessary, then download the program to my board.

And here is blink.c. We divide the 16MHz to 500Hz because we have only an 8 bit counter in TIM4, and also because 500Hz will be used in a larger application as a tick for the display update and button sensing. To get 1Hz we count to 250 each interrupt and flip the bit each time the counter overflows.

#define STM8S103

#include <stm8s_clk.h>
#include <stm8s_tim4.h>
#include <stm8s_itc.h>
#include <stm8s_gpio.h>

static uint8_t tim4_overflow = 0;

void tim4_isr(void) __interrupt(ITC_IRQ_TIM4_OVF)
{
        tim4_overflow = 1;                              // set flag
        TIM4_ClearITPendingBit(TIM4_IT_UPDATE);         // clear interrupt
}

int main()
{
        CLK_DeInit();
        CLK_HSICmd(ENABLE);                             // internal oscillator
        CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);        // 16MHz

        TIM4_DeInit();
        TIM4_TimeBaseInit(TIM4_PRESCALER_128, 249);     // freq = 500Hz
        TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);          // update on overflow
        TIM4_Cmd(ENABLE);

        GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_SLOW);        // LED

        enableInterrupts();                             // global interrupts

        for (;;) {
                // every 0.5 second flip the LED pin -> 1Hz
                for (uint8_t counter = 0; counter < 250; counter++) {
                        while (!tim4_overflow)          // busy wait for flag
                                ;
                        tim4_overflow = 0;              // clear flag
                }
                GPIO_WriteReverse(GPIOB, GPIO_PIN_5);
        }
}

API documentation

The original sources from STM, linked to in the top paragraph above contain a couple of CHM files. CHM files are compressed HTML pages used by Windows programs to provide help. On Linux they can be viewed with the okular program and perhaps others. Just put them somewhere convenient for you and open them with okular when you want to browse the library API documentation.

kenyapcomau, 2020-01-29

Clone this wiki locally