# 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: * `Wire` * `Adafruit_GFX` * `Adafruit_SSD1306` * `Adafruit_BusIO` (A dependency for the Adafruit libraries) ## Getting Started ### Prerequisites * [Arduino CLI](https://arduino.github.io/arduino-cli/installation/) * [STMicroelectronics STM32 core](https://github.com/stm32duino/Arduino_Core_STM32) ### Installation 1. **Install arduino-cli:** Follow the official instructions at [arduino.github.io/arduino-cli/installation/](https://arduino.github.io/arduino-cli/installation/). 2. **Initialize and Configure arduino-cli:** * Create a default configuration file: ```bash arduino-cli config init ``` * Add the STMicroelectronics board manager URL: ```bash arduino-cli config add board_manager.additional_urls https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json ``` * Update the local core index: ```bash arduino-cli core update-index ``` * Install the STM32 core: ```bash arduino-cli core install STMicroelectronics:stm32 ``` 3. **Install Required Libraries:** ```bash 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 1. **Prepare Your Sketch Directory:** Ensure your sketch file is named `SSD1306_sketch.ino` and is located in a folder with the same name. For example: `/path/to/your/project/SSD1306_sketch/SSD1306_sketch.ino` 2. **Compile the Sketch:** Compile the sketch for the Blue Pill (STM32F103CB or C8 with 128k), specifying the OpenOCD upload method. ```bash arduino-cli compile --fqbn STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103CB,upload_method=OpenOCDDapLink /path/to/your/project/SSD1306_sketch ``` The 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 `--verbose` flag. ## 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: ```bash /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](https://github.com/stm32duino/Arduino_Core_STM32/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: ```bash 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: ```bash nano platform.local.txt ``` Paste the following lines: ```bash 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.cfg` instead of `dapdirect_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. 1. Open the file `stm32f1xx_hal_msp.c` in your project. It is usually located in the `Src` or `Core/Src` directory. 2. Locate the `HAL_MspInit()` function. 3. Inside this function, find the line that disables the debug interface. It typically looks like this: ```c /**DISABLE: JTAG-DP Disabled and SW-DP Disabled */ __HAL_AFIO_REMAP_SWJ_DISABLE(); ``` 4. Replace it with the following line to keep SWD enabled while disabling the less-common JTAG interface: ```c /** 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.3V` * `SWDIO` -> `DIO` * `SWCLK` -> `CLK` * `GND` -> `G` * `nRST` -> `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. 1. Open the project file `../config/openocd_chip.cfg`. 2. Find the following line: ```tcl reset_config srst_only ``` 3. Change it to `none`: ```tcl reset_config none ``` 4. Save the file and try programming again.