SSD1306 OLED Servo Control with STM32 Blue Pill
This project demonstrates how to control a servo motor using an IBT_2 (BTS7960) motor driver, an STM32 Blue Pill, and a 128x64 SSD1306 OLED display. The user can control the motor's speed and direction using four push buttons, with real-time feedback on the OLED screen. It shows how to use the DAPLink programmer in Arduino IDE v2 with debugging.
Features
- Motor Control: Adjust speed and direction of a servo motor.
- OLED Display: A 128x64 SSD1306 OLED display shows the current speed, direction, and motor state (ON/OFF).
- User Interface: A simple and intuitive interface with four buttons for control (Up, Down, OK, Cancel).
- Two-Color Display Optimization: The UI is designed for two-color (Yellow and Blue) OLED displays, with a static header in the yellow section and dynamic values in the blue section.
Hardware Required
- STM32F103C8T6 "Blue Pill" development board
- 128x64 SSD1306 OLED display (I2C) with 4 push buttons (up, down, OK, Back)
- IBT_2 (dual BTS7960) motor driver
- Servo motor e.g.: RS-550 or R-775
- External power supply for the motor 12-24V/5A
- Breadboard and jumper wires
Wiring
Connect the components to the Blue Pill as described below.
OLED Display (I2C)
| OLED Display Pin | Blue Pill Pin |
|---|---|
| VCC | 3.3V |
| GND | GND |
| SCL | PB6 |
| SDA | PB7 |
Control Buttons
The buttons are connected to GPIO pins using the internal pull-up resistors. The other terminal of each button should be connected to GND.
| Button Function | Blue Pill Pin |
|---|---|
| Up | PA0 |
| Down | PA1 |
| OK | PA2 |
| Cancel | PA3 |
IBT_2 Motor Driver
The IBT_2 module requires its own power supply for the motor.
| IBT_2 Pin | Blue Pill Pin | Description |
|---|---|---|
| VCC | 5V | Logic Power |
| GND | GND | Logic Ground |
| R_EN | 3.3V | Right Enable (connect to 3.3V) |
| L_EN | 3.3V | Left Enable (connect to 3.3V) |
| RPWM | PB0 | Right PWM Signal (Forward) |
| LPWM | PB1 | Left PWM Signal (Reverse) |
DAPLink UART
For debugging and logging, you can connect the DAPLink's virtual COM port to the Blue Pill's UART1.
| DAPLink Pin | Blue Pill Pin | Description |
|---|---|---|
| RXD | PA9 (TX1) | Connect to TX |
| TXD | PA10 (RX1) | Connect to RX |
| GND | GND | Common Ground |
IBT_2 Power Connections:
| IBT_2 Terminal | Connection |
|---|---|
| B+ | Positive of Motor Power Supply |
| B- | Negative of Motor Power Supply |
| M+ | Positive of Servo Motor |
| M- | Negative of Servo Motor |
Dependencies
This sketch requires the following Arduino libraries:
WireAdafruit_GFXAdafruit_SSD1306Adafruit_BusIO(A dependency for the Adafruit libraries)
Getting Started
Prerequisites
Installation
-
Install arduino-cli: Follow the official instructions at arduino.github.io/arduino-cli/installation/.
-
Initialize and Configure arduino-cli:
- Create a default configuration file:
arduino-cli config init - Add the STMicroelectronics board manager URL:
arduino-cli config add board_manager.additional_urls https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json - Update the local core index:
arduino-cli core update-index - Install the STM32 core:
arduino-cli core install STMicroelectronics:stm32
- Create a default configuration file:
-
Install Required Libraries:
arduino-cli lib install "Adafruit SSD1306" "Adafruit GFX Library" "Adafruit BusIO"
Board Setup
In Arduino IDE → Tools, set:
Board → STM32 MCU based boards → Generic STM32F1 series
Board part number → BluePill F103CB (or C8 with 128K)
Upload Method → OpenOCD DAPLink (SWD)
Compilation
-
Prepare Your Sketch Directory: Ensure your sketch file is named
SSD1306_sketch.inoand is located in a folder with the same name. For example:/path/to/your/project/SSD1306_sketch/SSD1306_sketch.ino -
Compile the Sketch: Compile the sketch for the Blue Pill (STM32F103CB or C8 with 128k), specifying the OpenOCD upload method.
arduino-cli compile --fqbn STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103CB,upload_method=OpenOCDDapLink /path/to/your/project/SSD1306_sketchThe binary files will be generated in a temporary build directory. To find the path to the binary, you can run the compile command with the
--verboseflag.
Upload to the Board
The compiled sketch can be uploaded to the Blue Pill using openocd. The exact command may vary depending on your setup.
First, you need to find the path to your compiled .elf file. You can find this in the output of the arduino-cli compile command. It will be in a temporary directory ~/.cache/arduino/sketches.
Then, find the openocd e.g.: ~/.arduino15/packages/STMicroelectronics/tools/xpack-openocd/0.12.0-6/bin/openocd or install a distro specific version e.g.: sudo apt install openocd. Example of the path to the compiled sketch: /home/martin/.cache/arduino/sketches/96DBB1C909C240C2F96DCDD5DDFB9A12/SSD1306_sketch.ino.elf
Here is an example command to upload the sketch using DAPLink:
/path/to/your/openocd -d2 -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c "program {/path/to/your/sketch.ino.elf} verify reset exit"
🐞 Hardware Debugging with DAPLink (CMSIS-DAP) on Blue Pill
This section describes how to enable hardware debugging for the STM32F103 "Blue Pill" board using a DAPLink / CMSIS-DAP debugger in Arduino IDE 2.
By default, the STM32 Arduino core loads the wrong OpenOCD configuration (dapdirect_swd, meant for ST-Link).
Until the issues/2807 is not fixed, follow these steps to work around it:
🧭 1. Locate STM32 Core Folder (Linux)
Open a terminal and navigate to your STM32 Arduino core installation:
cd ~/.arduino15/packages/STMicroelectronics/hardware/stm32/2.11.0/
Adjust the version number if different (check in Arduino IDE → Tools → Board → Boards Manager).
🧰 2. Create or Edit platform.local.txt
Create (or edit) a local override file:
nano platform.local.txt
Paste the following lines:
debug.server.openocd.scripts.0=interface/cmsis-dap.cfg
debug.server.openocd.scripts.1={runtime.platform.path}/debugger/select_swd.cfg
Save and close (Ctrl + O, Enter, Ctrl + X).
These lines tell OpenOCD to:
-
Use the CMSIS-DAP interface
interface/cmsis-dap.cfg -
Use standard SWD transport
select_swd.cfginstead ofdapdirect_swd
🔁 3. Restart Arduino IDE
Completely close and reopen Arduino IDE 2 to apply the new settings.
⚙️ 4. Configure the IDE
In Arduino IDE → Tools, set:
-
Debug symbols and core logs → Core Logs and Symbols Enabled (-g)
-
Optimize → Debug (-Og)
Then click the 🐞 Debug icon and press Start Debugging.
Troubleshooting
1. Cannot Re-program Blue Pill After First Flash
This guide addresses an issue where a Blue Pill (STM32F103) board can be programmed successfully once with Embeetle, but all subsequent attempts fail with an error similar to Error: Error connecting DP: cannot read IDR.
Symptom: The OpenOCD output shows the following error on the second flash attempt:
Error: Error connecting DP: cannot read IDR
in procedure 'program'
** OpenOCD init failed **
The Cause
The root cause is that the application code reconfigures the debug pins (PA13 for SWDIO and PA14 for SWCLK) for other purposes. This effectively disables the Serial Wire Debug (SWD) interface, preventing the DAPLink programmer from establishing a connection.
The SWD interface can be activated manually by switching the BOOT0 jumper to 1 and the pressing reset button. However, this is inconvenient for normal development workflows.
The Solution
Change the configuration to keep the SWD interface enabled.
- Open the file
stm32f1xx_hal_msp.cin your project. It is usually located in theSrcorCore/Srcdirectory. - Locate the
HAL_MspInit()function. - Inside this function, find the line that disables the debug interface. It typically looks like this:
/**DISABLE: JTAG-DP Disabled and SW-DP Disabled */ __HAL_AFIO_REMAP_SWJ_DISABLE(); - Replace it with the following line to keep SWD enabled while disabling the less-common JTAG interface:
/** DISABLE: JTAG-DP Disabled but keep SW-DP Enabled */ __HAL_AFIO_REMAP_SWJ_NOJTAG();
2. Error: Unable to reset target
If you encounter the following error message in Embeetle's output console during a flashing attempt:
Error: timed out while waiting for target halted
embedded:startup.tcl:1813: Error: ** Unable to reset target **
in procedure 'program'
This typically means there is a mismatch between the reset strategy configured in OpenOCD and your physical wiring. By default, the project is configured to use a hardware reset, which requires the nRST pin to be connected.
Solution 1 (Recommended): Connect the Hardware Reset Pin
The most reliable solution is to ensure your wiring matches the default configuration.
Make sure the nRST pin of your DAPLink programmer is connected to the R (Reset) pin on the Blue Pill's board.
Your connections should be:
VCC->3.3VSWDIO->DIOSWCLK->CLKGND->GnRST->R
Solution 2 (Alternative): Use a Software Reset
If you prefer to use a 3-wire setup (SWDIO, SWCLK, GND) and not connect the reset pin, you must change the configuration to instruct OpenOCD to use software-based reset commands instead of toggling a physical pin.
- Open the project file
../config/openocd_chip.cfg. - Find the following line:
reset_config srst_only - Change it to
none:reset_config none - Save the file and try programming again.