Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time
Olimex STM32 P103 Development Kit Demos

This suite contains a number of small, simple demo programs for exercising the
various peripherals of the STM32 Microcontroller.

A makefile is included which can compile the demos,
program/debug the development board, and run/debug them in QEMU.

The makefile and linker scripts are intended to be run in a GNU/Linux environment.  

To compile, you need the ARM GCC compiler and utilities (arm-none-eabi-gcc,
arm-none-eabi-ld, arm-none-eabi-as, arm-none-eabi-objcopy,

I originally used the CodeSourcery G++ Lite toolchain for ARM (Sourcery CodeBench Lite 2012.03-56 for ARM EABI),
but this no longer appears to be supported. A 2013 version is available at,
but I was not able to run the installer on my machine.

I currently use the GNU Arm Embedded Toolchain located at (Version 10.3-2021.07).
To install this:
1) Download and unpack the Linux x86_64 Tarball (or approriate version)
2) Add the bin folder (Which contains the toolchain binaries) to the path using the following command:
     export PATH="/path_to_tarball_contents/bin:$PATH"
3) You are ready to compile stm32_p103_demos - see the "USING THE MAKEFILE" section below.

To run the QEMU examples, you need a modifed version of QEMU which contains the
STM32 peripherals.  This can be found at: .
The QEMU_ARM_DIR can be set to the location of the qemu_system_arm executable.
If the variable is not set, it defaults to ../qemu_stm32/arm-softmmu/ .

For the UART examples, I used cutecom as my terminal software.  For the echo
examples, you need to use the "No line end" option.  The FreeRTOS example needs
to have "LF line end". Otherwise it will send a line feed and overflow the UART
buffer (since we are not using flow control).  Connect with these settings:
9600 Baud Rate
8 Data bits
1 Stop bit

Note that the peripheral library knows the clock rate of the board via the
HSE_VALUE and HSI_VALUE macros in
libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x.h .

The following demos are provided.  All of them except blink_flash_asm are written
in C, and use ST's initialization library.

adc_single -
    Samples analog data using the Analog to Digitcal Converter (ADC).  This
    program performs a series of single samples and prints the results to the
    There are several modes.  To scroll through the modes, press the button on
    the development board:
    Mode 1 - Print the value of the internal temperature sensor.
             Also attempts to calculate the actual temperature using the formula
             in the reference manual.  On my board, this gives a high
             temperature which I assume is wrong.  Further investigation is
    Mode 2 - Print value of the internal voltage reference.
    Mode 3 - Print value on the external pin PC.0
    Mode 4 - A special mode that does not use the ADC, but prints
             the clock configuration.  This is useful for debugging.

    All numbers are hexadecimal except for the degrees celsius temperature. 

    One way to drive pin PC.0 with an analog signal is to use a
    potentiometer as follows:
           PC.0 --->/

blink_flash -
    Flashes the LED on and off

blink_flash_asm -
    Same as blink_flash, but written in assembly language.
    This is the simplest demo, and probably the best example
    for low-level troubleshooting.

button -
    Example of using the button in non-interrupt mode.  Continuously polls
    the button and toggles the LED when the button is pressed.  Note that this
    example does not seem to work well in QEMU.  When using "sendkey b"
    (see the button_int demo below), the LED does not toggle.  Perhaps
    this is a timing issue?

button_int -
    Example of external interrupts.  Toggles the LED every time the
    button is pressed.  Note that in QEMU, the button press is simulated
    by pressing the b key.  You will need to do this from the QEMU monitor,
    by typing the command "sendkey b".

button_int_infinite -
    Example of why the interrupt flag needs to be cleared.
    When the button is pressed, the interrupt fires,
    but the interrupt pending flag is not cleared.  This
    causes the interrupt to repeatedly fire.

c_mem_model - 
    Does not do anything.  Declares various variables so that the
    memory organization can be studied (by viewing the listing or
    running through the debugger).  There are also other listings (e.g. symbol
    listings) that you can produce, but these aren't automatically created
    by the makefile.

    Pending documentation...

freertos_singlethread -
    Example of using a real time operating system (FreeRTOS).  This runs a
    single task to flash the LED on and off.

freertos_multithread - 
    Example of using a real time operating system (FreeRTOS).  This
    runs the following tasks concurrently:
      1) Blink the LED.
      2) Print the string "Hello 1" to the RS232 port (twice a second).
      3) Print the string "Hello 2" to the RS232 port (once every two seconds).
      4) Listens to the RS232 port.  When you type a line and then hit
         the enter key, the line is echoed back.

    Pending documentation...

qemu_test -
    Tests changes made in the QEMU_STM32.  Unless you are really interested,
    you should probably skip this demo.

    Pending documentation...

software_int -
    Periodically generates a software interrupt that in turn toggles the LED.

    Tests the STKALIGN bit in the NVIC CCR register.  This example must be
    run in a debugger to verify the alignment is working.  I have had limited
    success with running this with QEMU.  Unless you are really interested,
    you should probably skip this demo.

    Uses the Cortex NVIC system tick timer to flash the LED.

    Uses the timer to count up and down.
    There are several modes.  To scroll through the modes, press the button on
    the development board:
    Mode 1 - Count up for five seconds.  Once five seconds have elapsed, the
             LED is toggled and the count resets to 1.
    Mode 2 - Similar to Mode 1, but counts down instead of up.
    Mode 3 - Similar to Modes 1 and 2, but alternately counts up and then down.
    Mode 4 - Counts in one-shot mode.  Each time the count is finished, the
             timer will be re-enabled to do another one shot count.
    Mode 4 - Counts up, but when the count reaches 3, the program interrupts the
             count using the UG flag.  This resets the count back to 1.
    Mode 6 - A special mode that does not use the timer, but prints
             the clock configuration.  This is useful for debugging.

`	All numbers are in decimal.

    * Note that the timer in QEMU STM32 does not behave exactly like real
      hardware.  In particular, the counting does not always go in the right
      direction, and the one shot mode does not appear to work properly.

    Tests the UART write functionality.  Continues to write the word "Hello"
    to the UART.  This example uses polling.

    Tests the UART write functionality, but using interrupts.  It
    repeatedly writes an X to the UART.

    Tests the UART read/write functionality.  Waits for a character to be
    received and then echoes the character back.  This example uses

    The same as uart_echo, except this example is interrupt driven.

    Contains the demo source code.
    Contains Eclipse debug launchers that can be imported into Eclipse.  Only
    launchers for the blink_flash example are included.  Other launchers can be
    created by duplicating these.
        Debug blink_flash
            Starts a remote debug session to debug the blink_flash program. This
            will connect to QEMU or to OpenOCD, both of which must be in debug
        Debug QEMU (blink_flash)
            Starts debugging QEMU's code while it is running the blink_flash
            example.  Note that the SIGUSR1 signal will keep firing, so you will
            need to disable the signal breakpoint, or the debugger will keep
    Contains shared libraries from external sources
    Contains CMSIS source code (a common API for ARM Cortex cores that is vendor
    independent) - copied from STMicro's V3.5.0.
    Note that the file CMSIS/CM3/DeviceSupport/ST/STM32F10x/stm32f10x.h has been 
    odified to uncomment the "#define STM32F10X_MD" and
    "#define USE_STDPERIPH_DRIVER" lines.
    Contains the FreeRTOS real time operating system source code - this is a
    copy of the Source folder from
    Contains STM32 peripheral libraries - copied from
    STMicro's V3.5.0
    Contains STM32 openocd configuration scripts.

The makefile contains targets that can be used to compile, run, and debug the
demo programs.

To compile one of the programs, run "make <program>_ALL"
e.g. "make blink_flash_ALL".  This will produce three files in the <program>
    main.bin -  The raw binary file.  Can be used to program the microcontroller
                or to run in QEMU.
    main.elf -  The program with debug symbols included.  Can be loaded into
                a debugger.
    main.list - A listing containing the entire program.  Can be examined to
                get disassembly, symbols, exact memory addresses, etc..
Running "make" or "make all" runs "make <program>_ALL" for all of the programs.

Programming a Microcontroller:
To program/debug a microcontroller, you will need a programmer that is compatible
with openocd, and you will need openocd installed.

To program the microcontroller with <program>, run 
  make <program>_PROG

By default it uses openocd and assumes you are using an
Olimex ARM-USB-TINYH programmer.  This can be overriden by changing the
OPENOCD_INTERFACE variable (or declaring an environment variable of the same
name).  Look inside the makefile for an example.  Once the microntroller is
programmed, the program will automatically start executing.

Running in QEMU:
See the DEPENDENCIES section for more details.  To run <program> in QEMU, run
    make <program>_QEMURUN

This should attach the RS232 UART (i.e. UART2) to standard in/out, but it
doesn't seem to work for me.  To test the UART, you can use one of these
    <program>_QEMURUN_PTY - Attaches UART2 to the PTY device.  QEMU will tell
                            you which PTY device to connect to.  If there
                            is too much text and the the PTY device line
                            scrolls off the console, you can also type
                            "info chardev" in the monitor and check the "serial0"
                            line to get the specific PTY device to connect to.
                            Sometimes I do not get any output from the UART
                            until I've typed a character or two (when using
                            cutecom to connect to the PTY device).  I don't
                            understand why, but maybe I'm doing something
    <program>_QEMURUN_TEL - Attaches UART2 to a telnet server at port 7777.

Debugging a Microcontroller:
To debug <program>, first program it into the Microcontroller.  Then
run "make DBG".  This will start openocd which
creates a GDB server at port 3333.  You can connect to it with GDB, or a GDB
based debugger (I use Eclipse).

Debugging in QEMU:
To debug <program> in QEMU, run "make <program>_QEMUDBG".  This will start QEMU
in debug mode, which sets up a GDB server at port 3333.  Note that this is the
same port used for debugging a microcontroller - once you have GDB set up for
debugging the Microcontroller, it should work interchangeably with QEMU and

ST Microelectronics STM32 website
	Specifically, see:
	"RM0008 Reference Manual"
	"PM0056 Programming manual"
	STM32F10x standard peripheral library - (contains library and examples)
	"STM32 More Than a Core - Circuit Cellar, Tom Cantrell"
	"AN3116 Application note: STM32's ADC Modes and their Applications"
Olimex "STM-P103 Development Board Users Manual Rev. A, April 2008"
Olimex STM32-P103 Website (with user manual, schematic, examples, etc.)
ARM "Cortex-M3 Technical Reference Manual"
"ARM v7-M Architecture Application Level Reference Manual"
"ARM v7-M Architecture Reference Manual"

Keil STM32 sample code

Hitex Development Tools "The Insider's Guide To The STM32 ARM Based Microcontroller"

SparkFun Forum Post - Flashing the Olimex STM32-P103 with OpenOCD r623 HOWTO

EE Times - "Building Bare-Metal ARM Systems with GNU"

Microcross "GNU ARM Assembler Quick Reference"
ARM "ELF for the ARM Architecture"

ARM "Thumb Instruction Set Quick Reference Card"

ST Microelectronics STM32F103xB datasheet

Balau Blog - "Hello world for bare metal ARM using QEMU"
OpenOCD User's Guide

Communit Ubuntu Documentation - OpenOCD "STM32/ARM Cortex-M3 HOWTO: Development under Ubuntu (Debian)"
MakingThings "Debug with OpenOCD" "How to setup OpenOCD under Linux?"
Jeroen Hermans "OpenOCD and Eclipse"

OpenHardware "Olimex ARM-USB-OCD"
Thank you to the following contributors:
Aunyx (
hankhank (
oska874 (


A suite of demo applications for the Olimex STM32 P103 Development Kit






No packages published

Contributors 4