# Install git, if you don't have it
curl -A MS https://webinstall.dev/git | powershell
# Install vcpkg
git clone https://github.com/microsoft/vcpkg
.\vcpkg\bootstrap-vcpkg.bat
pushd utah-rust-blue-pill-code/
# You have two options:# A) cargo flash (will build and deploy)
cargo flash --release --chip STM32F103C8
# B) cargo embed (will open debug console)# (relies on the Embed.toml)
cargo embed --release
# (you will need to hit ctrl+c to quit)
Peripherals
When you want to answer the question "How do I make x do y?", you'll be looking here:
(core peripherals) pac-style crate defining functionality common to all Cortex-M
Terms
Term
Desc
HAL
Hardware-Abstraction Layer
SVD
XML-description of CPU (such as ARM Cortex-M) or SoC (such as STM32)
NVIC
"Nested Vector" Interrupt Controller is how you get a notification to change control. Interrupts bubble up for dispatch.
SYST
SysTick (System Timer) a timer in all ARM processors for measuring intervals, sleeping, delaying, etc (OS-level)
----
---
FPU
Changes or observes the way that Math happens. Useful for really low-level debugging. On some CPUs this could be for directly writing numbers and reading results
rcc
Reset & Clock Control (reset peripheral is responsible for putting the hardware in a clean state, required even on boot)
push_pull_output
Actively tries to pull a signal high or low
Rust / HAL conventions.
Term
Desc
take()
there's only one of something and can only be had once
constrain()
change the shape of an API
freeze()
committing to a configuration, for the life of the program
split()
tracks pin ownership - rather than all 16 bits, for example
block!
used on synchronous calls that could be async (legacy?)
Sometimes random, seemingly unrelated things must be passed around.
Why does the clock need access to the clock?
Although the devices know what they need (as they have 1:1 types - such as apb2), it is explicit for the sake avoiding race or locking conditions, and for documentation to the reader.
Cleaning Up
Set the default rust toolchain version back to stable:
rustup default stable
Errors
Probe could not be created
cargo-flash 0.9.0 gives me this error. The instructions have been updated to use cargo-flash 0.8.0:
Finished release [optimized + debuginfo] target(s) in 1.15s
Flashing /Users/aj/BluePill_Rust/utah-rust-blue-pill-code/target/thumbv7m-none-eabi/release/blue_pill_base
Error Probe could not be created
Caused by:
0: Pipe error
1: Pipe error
Solution: Use cargo-flash 0.8.0.
Error The config 'default' could not be loaded.
Error The config 'default' could not be loaded.
Caused by:
enum Level does not have variant constructor Warn
Solution: Use cargo-embed 0.8.0, and update the config
diff --git a/Embed.toml b/Embed.toml
index 8a45ee4..e53456a 100644
--- a/Embed.toml
+++ b/Embed.toml
@@ -13,21 +13,25 @@ protocol = "Swd"
[default.flashing]
# Whether or not the target should be flashed.
enabled = true
-# Whether or not the target should be halted after flashing.
-halt_afterwards = false
# Whether or not bytes erased but not rewritten with data from the ELF
# should be restored with their contents before erasing.
restore_unwritten_bytes = false
# The path where an SVG of the assembled flash layout should be written to.
# flash_layout_output_path = "out.svg"
+[default.reset]
+# Whether or not the target should be reset.
+enabled = true
+# Whether or not the target should be halted after flashing.
+halt_afterwards = false
+
[default.general]
# The chip name of the chip to be debugged.
chip = "stm32f103C8"
# A list of chip descriptions to be loaded during runtime.
chip_descriptions = []
# The default log level to be used.
-log_level = "Warn"
+log_level = "WARN"
[default.rtt]
# Whether or not an RTTUI should be opened after flashing.
Prior Versions
The last time we did this workshop we used these versions:
Rust v1.46.0
cargo-flash v0.8.0
cargo-embed v0.8.0
[](https://www.youtube.com/watch?v=2tGSJpbZVS8&list=PLDWmoWFf46givBRQmh5DyE27OsXMJPfag)
# Prerequisites (long download + compile)
IMPORTANT!! These steps can easily take **30 MINUTES** of downloading and compiling
### 1. Install basic compiler tools
**Mac**
```bash
# Install XCode Command-Line Tools, if you haven't already
xcode-select --install
```
**Linux**
```bash
sudo apt install -y git build-essential pkg-config
```
**Windows 10**
```pwsh
# Install git, if you don't have it
curl -A MS https://webinstall.dev/git | powershell
# Install vcpkg
git clone https://github.com/microsoft/vcpkg
.\vcpkg\bootstrap-vcpkg.bat
```
### 2. Install `rust`
Mac, Linux:
1. Install Rust
```bash
curl https://webinstall.dev/rust | bash
export PATH="$HOME/.local/bin:$PATH"
pathman add ~/.cargo/bin
export PATH="$HOME/.cargo/bin:$PATH"
```
2. Close and re-open your terminal
Note: Follow any on-screen instructions from the rust installer.
We want to make sure that we're all on the same version:
```bash
rustup update
rustup toolchain install stable
rustup toolchain install 1.59.0
rustup default 1.59.0
```
Note: see https://rustup.rs for Windows 10.
#### FYI: Toolchain Version Locking
Each directory can have its own Rust config. You can explicitly set the version of rust to use for that code.
Let's say you're going to run all of these examples from `~/blue_pill`:
```bash
mkdir -p ~/blue_pill/
pushd ~/blue_pill/
```
For this workshop we'll use v1.59.0:
```bash
rustup override set 1.59.0
```
Also, you can explicitly compile a rust program with a particular rust version:
```bash
rustup run 1.59.0 \
cargo install cargo-flash --version 0.12.1
```
### 3. Add the ARM Cortex-M toolchain
```bash
rustup target install thumbv7m-none-eabi
```
### 4. Install the ftdi USB driver
**Mac**
```bash
# Install brew, if you haven't already
curl -sS https://webinstall.dev/brew | bash
# Install libftdi
brew install libftdi
```
**Linux**
```bash
sudo apt install -y pkg-config libusb-dev libusb-1.0 libftdi1-dev
```
**Windows 10**
```pwsh
# Install ftdi
vcpkg install libftdi1:x64-windows-static-md libusb:x64-windows-static-md
```
### 5. Install `cargo flash` for Rust 1.59.0
```bash
rustup run 1.59.0 \
cargo install cargo-flash --version 0.12.1
rustup run 1.59.0 \
cargo install cargo-embed --version 0.12.0
```
# STOP
Did you read the prerequisites ^^?
# Workshop (NOT Prerequisites)
## 1. Download and Print the schematics
- https://cgit.pinealservo.com/BluePill_Rust/resources/raw/branch/master/The-Generic-STM32F103-Pinout-Diagram.pdf
- https://cgit.pinealservo.com/BluePill_Rust/resources/raw/branch/master/STM32F103C8T620Schematic.pdf
## 2. Clone the docs repository
```bash
mkdir ~/blue_pill/
pushd ~/blue_pill/
git clone https://cgit.pinealservo.com/BluePill_Rust/resources.git ./resources
```
## 3. Clone the code repository
```bash
mkdir ~/blue_pill/
pushd ~/blue_pill/
git clone https://cgit.pinealservo.com/BluePill_Rust/blue_pill_base ./base/
pushd ./base/
# NOTE: we probably don't need this step now
git reset --hard 5db28da
```
## 4. Connect the pill to programmer
The pin order on the programmer **may not exactly match** the pin order on the board
In _most_ of the parts in the kit, this is what the PIN order looks like:
| Blue Pill | Programmer (Kit) |
| --------- | ---------- |
| GND | 3.3v (7,8) |
| SWCLK | GND (5,6) |
| SWDIO | SWDIO (4) |
| 3.3v | SWCLK (2) |
**Example only** of programmer pinout (not the same as yours):

DOUBLE CHECK!!!
- the same color power wire is going to a pin marked 3.3v on both the programmer and the blue pill
- the same color ground wire is going into a pin marked GND on both
Failure to double check == fried board!
### Windows 10 STLink Driver
If you're on Windows 10, be sure to install the STLink driver:
- https://www.st.com/en/development-tools/stsw-link009.html
### Connect Programmer to Computer
Uncap the programmer and plug into a USB port on your computer.
Again: bad 3.3v or GND connection == fried board!
### How to know if it worked?
The blue pill should boot up with both
- **red power light**
- **blinking green light**
If it does not, it could be that it was not programmed with the "hello, world" application.
#### `--list-probes`
```bash
cargo flash --list-probes
```
```txt
The following devices were found:
[0]: STLink V2 (VID: 0483, PID: 3748, Serial: nGS8LN, STLink)
```
Note: If you have multiple STLinks connected, you'll want to edit `Embed.toml` (or maybe it was `Cargo.toml` with those values.
#### Console.app on Mac
If you're on Mac you can open Console.app and searching `icdd` and `stm32` from the top-level logs (your computer name).
Unplug and re-plug the programmer device and you should see something like this:
```txt
default 20:01:35.105575 -0600 icdd #ICDebug - 23:{ICWiredBrowser.m} (USB Device first match)
default 20:01:35.106397 -0600 icdd #ICDebug - 388:{ICWiredBrowser.m} (8 USB Descriptions Managed)
default 20:01:35.109018 -0600 icdd #ICDebug - 457:{ICDDMessageCenter.m} (+Add STM32 STLink - 0x0/0x0/0x0 - 0x14200000 - ICDeviceDescriptionSUQuery)
default 20:01:35.172790 -0600 icdd #ICDebug - 205:{ICResourceManager.m} (6E009300-0800-0100-1000-130047005300|STM32 STLink|MANUFACTURER:STMicroelectronics;MODEL:STM32 STLink|SW=FALSE|)
default 20:01:35.179788 -0600 icdd #ICDebug - 457:{ICDDMessageCenter.m} (+Add STM32 STLink - 0x0/0x0/0x0 - 0x14200000 - ICDeviceDescriptionAdded)
default 20:01:36.620079 -0600 icdd #ICDebug - 37:{ICWiredBrowser.m} (USB Interface first match)
default 20:01:36.621099 -0600 icdd #ICDebug - 388:{ICWiredBrowser.m} (9 USB Descriptions Managed)
default 20:01:36.626026 -0600 icdd #ICDebug - 205:{ICResourceManager.m} (00000000-0000-0000-0000-000004833748|STM32 STLink|(null)|SW=FALSE|)
default 20:01:36.626032 -0600 icdd #ICDebug - 457:{ICDDMessageCenter.m} (+Add STM32 STLink - 0xff/0xff/0xff - 0x14200000 - ICDeviceDescriptionSUQuery)
default 20:01:36.630364 -0600 icdd #ICDebug - 457:{ICDDMessageCenter.m} (+Add STM32 STLink - 0xff/0xff/0xff - 0x14200000 - ICDeviceDescriptionUndefined)
```
## 5. Build the sample code
```bash
pushd utah-rust-blue-pill-code/
# You have two options:
# A) cargo flash (will build and deploy)
cargo flash --release --chip STM32F103C8
# B) cargo embed (will open debug console)
# (relies on the Embed.toml)
cargo embed --release
# (you will need to hit ctrl+c to quit)
```
# Peripherals
When you want to answer the question "How do I make _x_ do _y_?", you'll be looking here:
- [(RM0008) STM32F10xxx Reference manual](https://cgit.pinealservo.com/BluePill_Rust/resources/src/branch/master/STM32%20Manuals/STM32F10xxx_ReferenceManual.pdf)
- [stm32f1xx_hal::pac](https://docs.rs/stm32f1xx-hal/0.2.1/stm32f1xx_hal/pac/index.html)
### I2C
Beginning of each transaction sends the address. Only the listener listens.
| I2C | I Squared C (like USB for microcontrollers) |
| ---- | ------------------------------------------- |
| SDAx | Data |
| SCLx | Clock 100kHz (slow) - 400kHz (fast) |
- 0.96 OLED Display: [Search: rust hal stm32 0.96 oled](https://www.google.com/search?q=rust+hal+stm32+0.96+oled) (hint: SSD1306)
- Bonus: [Search: rust embedded graphics](https://www.google.com/search?q=rust+embedded+graphics)
### SPI
Has chip select.
| CS |
| --- |
| 0x1 |
| 1x2 |
| 2x4 |
| 3x8 |
Rotary Encoder: [Search: stm32 hal rust rotary encoder](https://www.google.com/search?q=stm32+hal+rust+rotary+encoder)
### Timers
Each timer has certain constraints
TxCxN
# Libraries
| Lib | Desc |
| --- | --- |
| [`rtt_target`][rt] | Real-Time Trace - allows debug even whether or not a debugger is connected|
| [`stm32f1xx_hal::pac`][halp] | (SoC Peripherals) **P**eripheral **A**ccess **C**rate - autogenerated from SVD (like ARM-standardized XML description |
| [`cortex_m`][cm] | (core peripherals) *pac*-style crate defining functionality common to all Cortex-M |
[halp]: https://docs.rs/stm32f1xx-hal/0.2.1/stm32f1xx_hal/pac/index.html
[rt]: https://crates.io/crates/rtt_target
[cm]: https://crates.io/crates/cortex-m
# Terms
| Term | Desc |
| ---- | ----- |
| HAL | Hardware-Abstraction Layer |
| SVD | XML-description of CPU (such as ARM Cortex-M) or SoC (such as STM32) |
| NVIC | "Nested Vector" Interrupt Controller is how you get a notification to change control. Interrupts bubble up for dispatch. |
| SYST | _SysTick_ (System Timer) a timer in all ARM processors for measuring intervals, sleeping, delaying, etc (OS-level) |
| ---- | --- |
| FPU | Changes or observes the way that Math happens. Useful for _really_ low-level debugging. On some CPUs this could be for directly writing numbers and reading results |
| `rcc` | Reset & Clock Control (reset peripheral is responsible for putting the hardware in a clean state, required even on boot) |
| push_pull_output | Actively tries to pull a signal high or low |
Rust / HAL conventions.
| Term | Desc |
| ----------- | ----- |
| take() | there's only one of something and can only be had once |
| constrain() | change the shape of an API |
| freeze() | committing to a configuration, for the life of the program |
| split() | tracks pin ownership - rather than all 16 bits, for example |
| block! | used on synchronous calls that could be async (legacy?) |
Sometimes random, seemingly unrelated things must be passed around.
- Why does the clock need access to the clock?
Although the devices know what they need (as they have 1:1 types - such as `apb2`), it is explicit for the sake avoiding race or locking conditions, and for documentation to the reader.
## Cleaning Up
Set the default rust toolchain version back to `stable`:
```
rustup default stable
```
# Errors
## Probe could not be created
`cargo-flash 0.9.0` gives me this error. The instructions have been updated to use `cargo-flash 0.8.0`:
```
Finished release [optimized + debuginfo] target(s) in 1.15s
Flashing /Users/aj/BluePill_Rust/utah-rust-blue-pill-code/target/thumbv7m-none-eabi/release/blue_pill_base
Error Probe could not be created
Caused by:
0: Pipe error
1: Pipe error
```
#### Solution: Use `cargo-flash 0.8.0`.
## Error The config 'default' could not be loaded.
```txt
Error The config 'default' could not be loaded.
Caused by:
enum Level does not have variant constructor Warn
```
#### Solution: Use `cargo-embed 0.8.0`, and update the config
```diff
diff --git a/Embed.toml b/Embed.toml
index 8a45ee4..e53456a 100644
--- a/Embed.toml
+++ b/Embed.toml
@@ -13,21 +13,25 @@ protocol = "Swd"
[default.flashing]
# Whether or not the target should be flashed.
enabled = true
-# Whether or not the target should be halted after flashing.
-halt_afterwards = false
# Whether or not bytes erased but not rewritten with data from the ELF
# should be restored with their contents before erasing.
restore_unwritten_bytes = false
# The path where an SVG of the assembled flash layout should be written to.
# flash_layout_output_path = "out.svg"
+[default.reset]
+# Whether or not the target should be reset.
+enabled = true
+# Whether or not the target should be halted after flashing.
+halt_afterwards = false
+
[default.general]
# The chip name of the chip to be debugged.
chip = "stm32f103C8"
# A list of chip descriptions to be loaded during runtime.
chip_descriptions = []
# The default log level to be used.
-log_level = "Warn"
+log_level = "WARN"
[default.rtt]
# Whether or not an RTTUI should be opened after flashing.
```
## Prior Versions
The last time we did this workshop we used these versions:
- Rust v1.46.0
- cargo-flash v0.8.0
- cargo-embed v0.8.0
error: failed to compile cargo-flash v0.12.1, intermediate artifacts can be found at /var/folders/lv/_3rx8wmx1bd7mzc6h3pfxrr00000gn/T/cargo-installU9W0Cb
I have issue in rustup run 1.59.0
cargo install cargo-flash --version 0.12.1
error: failed to compile `cargo-flash v0.12.1`, intermediate artifacts can be found at `/var/folders/lv/_3rx8wmx1bd7mzc6h3pfxrr00000gn/T/cargo-installU9W0Cb`
Pls help-me
error: failed to compile `cargo-flash v0.12.1`, intermediate artifacts can be found at `/var/folders/lv/_3rx8wmx1bd7mzc6h3pfxrr00000gn/T/cargo-installU9W0Cb`
I stay in catalina.
https://cgit.pinealservo.com/BluePill_Rust/resources/issues/1
I did all the same commands as the link above:
I have issue in **rustup run 1.59.0 \
cargo install cargo-flash --version 0.12.1**
error: failed to compile `cargo-flash v0.12.1`, intermediate artifacts can be found at `/var/folders/lv/_3rx8wmx1bd7mzc6h3pfxrr00000gn/T/cargo-installU9W0Cb`
Pls help-me
Prerequisites (long download + compile)
IMPORTANT!! These steps can easily take 30 MINUTES of downloading and compiling
1. Install basic compiler tools
Mac
Linux
Windows 10
2. Install
rust
Mac, Linux:
Note: Follow any on-screen instructions from the rust installer.
We want to make sure that we're all on the same version:
Note: see https://rustup.rs for Windows 10.
FYI: Toolchain Version Locking
Each directory can have its own Rust config. You can explicitly set the version of rust to use for that code.
Let's say you're going to run all of these examples from
~/blue_pill
:For this workshop we'll use v1.59.0:
Also, you can explicitly compile a rust program with a particular rust version:
3. Add the ARM Cortex-M toolchain
4. Install the ftdi USB driver
Mac
Linux
Windows 10
5. Install
cargo flash
for Rust 1.59.0STOP
Did you read the prerequisites ^^?
Workshop (NOT Prerequisites)
1. Download and Print the schematics
2. Clone the docs repository
3. Clone the code repository
4. Connect the pill to programmer
The pin order on the programmer may not exactly match the pin order on the board
In most of the parts in the kit, this is what the PIN order looks like:
Example only of programmer pinout (not the same as yours):
DOUBLE CHECK!!!
Failure to double check == fried board!
Windows 10 STLink Driver
If you're on Windows 10, be sure to install the STLink driver:
Connect Programmer to Computer
Uncap the programmer and plug into a USB port on your computer.
Again: bad 3.3v or GND connection == fried board!
How to know if it worked?
The blue pill should boot up with both
If it does not, it could be that it was not programmed with the "hello, world" application.
--list-probes
Note: If you have multiple STLinks connected, you'll want to edit
Embed.toml
(or maybe it wasCargo.toml
with those values.Console.app on Mac
If you're on Mac you can open Console.app and searching
icdd
andstm32
from the top-level logs (your computer name).Unplug and re-plug the programmer device and you should see something like this:
5. Build the sample code
Peripherals
When you want to answer the question "How do I make x do y?", you'll be looking here:
I2C
Beginning of each transaction sends the address. Only the listener listens.
SPI
Has chip select.
Rotary Encoder: Search: stm32 hal rust rotary encoder
Timers
Each timer has certain constraints
TxCxN
Libraries
rtt_target
stm32f1xx_hal::pac
cortex_m
Terms
rcc
Rust / HAL conventions.
Sometimes random, seemingly unrelated things must be passed around.
Although the devices know what they need (as they have 1:1 types - such as
apb2
), it is explicit for the sake avoiding race or locking conditions, and for documentation to the reader.Cleaning Up
Set the default rust toolchain version back to
stable
:Errors
Probe could not be created
cargo-flash 0.9.0
gives me this error. The instructions have been updated to usecargo-flash 0.8.0
:Solution: Use
cargo-flash 0.8.0
.Error The config 'default' could not be loaded.
Solution: Use
cargo-embed 0.8.0
, and update the configPrior Versions
The last time we did this workshop we used these versions:
Hey @coolaj86 what does that part about "SPI Has chip select" mean? Do I need to do any jumper settings? Thanks!!!
error: failed to compile
cargo-flash v0.12.1
, intermediate artifacts can be found at/var/folders/lv/_3rx8wmx1bd7mzc6h3pfxrr00000gn/T/cargo-installU9W0Cb
I stay in catalina.
#1
I did all the same commands as the link above:
I have issue in rustup run 1.59.0
cargo install cargo-flash --version 0.12.1
@neuberfran You may have better luck with the instructions in the wiki here: https://cgit.pinealservo.com/BluePill_Rust/resources/wiki/Software-Setup