STM32F1xx micro-controller C firmware template
Go to file
King Kévin ac4731928b Merge branch 'clock_jockey' of into clock_jockey 2020-01-12 16:00:32 +01:00
lib USB: set project name as product string 2020-01-12 15:53:36 +01:00
libopencm3@a8a92b4c11 update libopencm3 2020-01-10 12:52:11 +01:00
.gitignore cherry-pick from busvoodoo branch, part 2 2018-02-18 15:20:01 +01:00
.gitmodules remove STM32duino-bootloader 2016-08-14 19:03:17 +02:00
Doxyfile doc: fix documentation 2020-01-03 00:16:59 +01:00
LICENSE.txt add GPLv3 license file 2018-02-13 15:14:10 +01:00 README: remove other boord details 2020-01-12 15:53:36 +01:00
Rakefile Rakefile: sepcify board for project 2020-01-12 15:53:36 +01:00
application.c application: improve motor not spinning protection 2020-01-12 15:53:36 +01:00
application.ld ld: update ld script to updated libopencm3 2020-01-12 15:52:27 +01:00
bootloader.c doc: fix documentation 2020-01-03 00:16:59 +01:00
bootloader.ld ld: limit to 64kB flash to be compatible with most MCU 2020-01-12 15:54:24 +01:00
global.c global: update pin definitions 2019-12-21 20:02:33 +01:00
global.h global: define RST as DFU force input 2020-01-12 15:53:36 +01:00



this clock jockey monitors the tachometer of a motor turning a clock, and regulates its speed by switching the power to it.


the goal was to make a round clock quadrant turn. the quadrant is made out of wood, around 1 m heigh, and weights around 5 kg. it is mounted on a disco ball base. the bearing is strong enough to hold it and allow the clock to turn around its center.

originally the disco ball base included a motor, but it was too fragile to withhold the forces. two plastic gears in the gear box broke. this was the state of the clock when I joined the team. I decided to fix the turning clock. the small DC or stepper motor I tried were too weak to turn the clock. I decided to use a universal motor salvaged from a washing machine.

the pinout of the motor was undocumented, but not hard to figure out. two wires went to a small module at the end of the rotor shaft. this is the tachometer to measure the rotation speed. it is also easy to trace the two wires going to the brushes feeding the power to the rotor coils. next, measure the resistance of the remaining pin pairs. one will have 0 Ohms. this is the fuse to protect against over-heating. there will be two pairs of 0.6 Ohms, and one of 1.2 Ohms. these are the two coils for the stator, with a center tap.

wire the motor with 220V AC the following way: AC L - fuse - rotor - stator (2 coils, not center tap) - AC N to limit the speed I used a 4000 W capable SCR. the SCR was not enough to regulate the motor speed. setting the potentiometer to a fixed point would results in the motor to stop turning after some time, of to speed up to fast. the user would have to adjust the potentiometer using then knob periodically to have a somewhat constant speed.

to overcome this limitation I developed the clock jockey. this device will monitor the speed of the motor using the tachometer, and switch the power to the motor using a Solid State Relay (SSR), so to reach and stay at the predefined speed.

the motor tachometer provides an AC signal. basically it's a generating motor linked to the shaft of the actual motor. the AC frequency (and voltage) indicates the speed of the motor. the AC signal is rectified using a full bridge rectifier. the rectified signal is input to an PC817 optocoupler (with ~ 200 Ohm inline resistor). the full bridge rectifier protects to optocoupler, which has a reverse breakdown voltage of 6 V, lower than the seen -10 V peaks of the AC signal. it also allows to get two pulses per AC period, for a more accurate speed measurement. the optocoupler is directly connected to the clock jockey. an omron G3MB-202P (5V) is also connected to the clock jockey to switch to power going to the motor. the SCR is still in line to limit the maximum delivered power.


the device reuses an ST-LINK/V2 clone. this board uses a STM32F103C8T6 micro-controller.

since the device is firmware protected (against read-out), you will first need to remove this protection using an SWD adapter and running rake remove_protection. you can then flash the bootloader using SWD and application using DFU a documented in the section below.


connect the peripherals the following way:

  • PC817X emitter, SWIM pin (PB11, pulled up to 3V3 on board)
  • PC817X collector, GND
  • G3MB-202P SSR 3+, 5V (5V required by SSR, with embedded resistor)
  • G3MB-202P SSR 4-, SWDIO (SWCLK pin in not 5V tolerant)

all pins are configured using defines in the corresponding source code.


the firmware will simply count the number of optocoupler falling edges (2 per revolution). it will periodically compare this count to the target value. if this is below, the SSR will be switched on. if it is above, the SSR will be switched off.

to set this target, connect the clock jokey to a computer. it will appear as a serial device (using the CDC ACM USB profile). use a serial terminal program and connect to it (the baud rate does not matter). enter tacho xx, with xx being the target tachometer count. to view the set and current tachometer values, enter tacho.

the target tachometer count is somewhat relative. it is proportional to the motor speed and tied to the periodic check (currently set to 0.1 s).

if the tacho count it at 0 for too many seconds after boot, the clock jockey will with off the power. this is a safety feature since the tachometer is either not reading the speed, or the motor is stuck.



The source code uses the libopencm3 library. The projects is already a git submodules. It will be initialized when compiling the firmware. Alternatively you can run once: git submodule init and git submodule update.


To compile the firmware run rake.


To generate doxygen documentation run rake doc.


There are two firmware images: bootloader and application. The bootloader image allows to flash the application over USB using the DFU protocol. The bootloader is started first and immediately jumps to the application if it is valid and the DFU mode is not forced (i.e. by pressing the user button on the board or requesting a DFU detach in the application). The application image is the main application and is implemented in application.c. It is up to the application to advertise USB DFU support (i.e. as does the provided USB CDC ACM example).

The bootlaoder image will be flashed using SWD (Serial Wire Debug). For that you need an SWD adapter. The Makefile uses a Black Magic Probe (per default), or a ST-Link V2 along OpenOCD software. To flash the booltoader using SWD run rake flash_booloader.

Once the bootloader is flashed it is possible to flash the application over USB using the DFU protocol by running rake flash. To force the bootloader to start the DFU mode, short the RST pin to the nearby ground pin. It is also possible to flash the application image using SWD by running rake flash_application.


SWD also allows to debug the code running on the micro-controller using GDB. To start the debugging session run rake debug.


The firmware offers serial communication over USB (using the CDC ACM device class).