Initial commit
This commit is contained in:
28
GEMINI.md
Normal file
28
GEMINI.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# STM32 Bluepill Quickstart
|
||||||
|
|
||||||
|
## Temporary files
|
||||||
|
Create files and directories within the project temp directory e.g.: `~/.gemini/tmp/d9929d1c794fb414052498bc12a08fef640ff8b7c30d9190d0699962781facbf`
|
||||||
|
|
||||||
|
## Compilation
|
||||||
|
|
||||||
|
To compile the sketch, run the following command from the project root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
arduino-cli compile --fqbn STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103CB,upload_method=OpenOCDDapLink --build-path /tmp/$(basename $(pwd)) .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flashing
|
||||||
|
|
||||||
|
To flash the sketch use `openocd` to flash the sketch.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
openocd -d2 -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c "program {/tmp/$(basename $(pwd))/$(basename $(pwd)).ino.elf} verify reset exit"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Viewing Logs
|
||||||
|
|
||||||
|
The best way for me to read the logs is to capture the output from the serial port to a file, and then read that file.
|
||||||
|
|
||||||
|
1. First, I'd configure the serial port settings without starting an interactive session using `stty`.
|
||||||
|
2. Then, I'd use a command like `head` to read a specific number of lines from the serial port and save them to a temporary file. This command will exit automatically after reading the lines.
|
||||||
|
3. Finally, I would use `read_file` to read the contents of that temporary file.
|
||||||
205
Readme.md
Normal file
205
Readme.md
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
## 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 (bug)[https://github.com/stm32duino/Arduino_Core_STM32/issues/2807] is not fixed, follow these steps to fix 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.
|
||||||
139
SSD1306_sketch.ino
Normal file
139
SSD1306_sketch.ino
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
|
||||||
|
// Screen dimensions
|
||||||
|
#define SCREEN_WIDTH 128
|
||||||
|
#define SCREEN_HEIGHT 64
|
||||||
|
|
||||||
|
// OLED display setup
|
||||||
|
#define OLED_RESET -1
|
||||||
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||||
|
|
||||||
|
// Button pins
|
||||||
|
#define UP_BUTTON_PIN PA0
|
||||||
|
#define DOWN_BUTTON_PIN PA1
|
||||||
|
#define OK_BUTTON_PIN PA2
|
||||||
|
#define CANCEL_BUTTON_PIN PA3
|
||||||
|
|
||||||
|
// IBT_2 Motor Driver pins
|
||||||
|
#define RPWM_PIN PB0
|
||||||
|
#define LPWM_PIN PB1
|
||||||
|
|
||||||
|
// Motor control variables
|
||||||
|
int motorSpeed = 0;
|
||||||
|
bool motorDirection = true; // true for forward, false for reverse
|
||||||
|
bool motorEnabled = false;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// Initialize OLED display
|
||||||
|
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||||
|
Serial.println(F("SSD1306 allocation failed"));
|
||||||
|
for(;;);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button pin setup with internal pull-up resistors
|
||||||
|
pinMode(UP_BUTTON_PIN, INPUT_PULLUP);
|
||||||
|
pinMode(DOWN_BUTTON_PIN, INPUT_PULLUP);
|
||||||
|
pinMode(OK_BUTTON_PIN, INPUT_PULLUP);
|
||||||
|
pinMode(CANCEL_BUTTON_PIN, INPUT_PULLUP);
|
||||||
|
|
||||||
|
// Motor driver pin setup
|
||||||
|
pinMode(RPWM_PIN, OUTPUT);
|
||||||
|
pinMode(LPWM_PIN, OUTPUT);
|
||||||
|
|
||||||
|
updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
bool needsUpdate = false;
|
||||||
|
|
||||||
|
// Button handling
|
||||||
|
if (digitalRead(UP_BUTTON_PIN) == LOW) {
|
||||||
|
Serial.println("Up button pressed");
|
||||||
|
motorSpeed += 5;
|
||||||
|
if (motorSpeed > 255) motorSpeed = 255;
|
||||||
|
needsUpdate = true;
|
||||||
|
delay(100); // Simple debounce
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(DOWN_BUTTON_PIN) == LOW) {
|
||||||
|
Serial.println("Down button pressed");
|
||||||
|
motorSpeed -= 5;
|
||||||
|
if (motorSpeed < 0) motorSpeed = 0;
|
||||||
|
needsUpdate = true;
|
||||||
|
delay(100); // Simple debounce
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(OK_BUTTON_PIN) == LOW) {
|
||||||
|
Serial.println("OK button pressed");
|
||||||
|
motorEnabled = !motorEnabled;
|
||||||
|
needsUpdate = true;
|
||||||
|
delay(200); // Simple debounce
|
||||||
|
}
|
||||||
|
|
||||||
|
if (digitalRead(CANCEL_BUTTON_PIN) == LOW) {
|
||||||
|
Serial.println("Cancel button pressed");
|
||||||
|
motorDirection = !motorDirection;
|
||||||
|
needsUpdate = true;
|
||||||
|
delay(200); // Simple debounce
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only update the display if a button was pressed
|
||||||
|
if (needsUpdate) {
|
||||||
|
updateDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update motor driver
|
||||||
|
if (motorEnabled) {
|
||||||
|
if (motorDirection) {
|
||||||
|
analogWrite(RPWM_PIN, motorSpeed);
|
||||||
|
analogWrite(LPWM_PIN, 0);
|
||||||
|
} else {
|
||||||
|
analogWrite(RPWM_PIN, 0);
|
||||||
|
analogWrite(LPWM_PIN, motorSpeed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
analogWrite(RPWM_PIN, 0);
|
||||||
|
analogWrite(LPWM_PIN, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDisplay() {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
|
||||||
|
// --- TOP YELLOW SECTION (Labels) ---
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setCursor(5, 4);
|
||||||
|
display.print("SPEED");
|
||||||
|
display.setCursor(50, 4);
|
||||||
|
display.print("DIR");
|
||||||
|
display.setCursor(95, 4);
|
||||||
|
display.print("STATE");
|
||||||
|
display.drawLine(0, 15, 127, 15, SSD1306_WHITE); // Separator line
|
||||||
|
|
||||||
|
// --- BOTTOM BLUE SECTION (Values) ---
|
||||||
|
display.setTextSize(2);
|
||||||
|
|
||||||
|
// Display Speed Value with padding for alignment
|
||||||
|
display.setCursor(0, 25);
|
||||||
|
if (motorSpeed < 10) {
|
||||||
|
display.print(" ");
|
||||||
|
} else if (motorSpeed < 100) {
|
||||||
|
display.print(" ");
|
||||||
|
}
|
||||||
|
display.print(motorSpeed);
|
||||||
|
|
||||||
|
// Display Direction Value
|
||||||
|
display.setCursor(45, 25);
|
||||||
|
display.print(motorDirection ? "FWD" : "REV");
|
||||||
|
|
||||||
|
// Display State Value
|
||||||
|
display.setCursor(95, 25);
|
||||||
|
display.print(motorEnabled ? "ON" : "OFF");
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user