Files
kttl/etc/rotary.md
T
2026-06-30 11:32:12 +10:00

131 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Rotary Encoder — Setpoint Control Wiring
Adds an EC11-class incremental rotary encoder to the kttl controller so the
temperature **setpoint** can be dialled in live, and so the encoder's
**push-switch** acts as the on-switch (identical to the board's B1 button).
Target board: **STM32F4-Discovery (STM32F411VE)**. Firmware: `src/main.rs`
(`SetpointKnob`, TIM1 in encoder mode).
---
## 1. Pin assignment
| Encoder leg | Discovery pin | Function | Extra parts |
|-----------------|------------------|---------------------------|-----------------------------|
| **A** (CLK) | **PE9** (TIM1_CH1) | quadrature channel A | 10 kΩ → 3V, 100 nF → GND |
| **B** (DT) | **PE11** (TIM1_CH2) | quadrature channel B | 10 kΩ → 3V, 100 nF → GND |
| **C** (common) | **GND** | rotary common | — |
| **SW1** | **3V** | push-switch leg | — |
| **SW2** | **PA0** | push-switch leg (‖ B1) | — |
| mount ×2 | **GND** | shield / mechanical | optional |
> **Use 3V, not 5V.** The STM32F411 is a 3.3 V part; the pull-ups set the logic
> high level seen by the pins, and the switch drives PA0 directly. 3V matches
> the MCU and the existing B1 button exactly — no level shifting.
---
## 2. Schematic
```
STM32F4-Discovery Rotary encoder (EC11, 7-leg)
┌──────────────┐
│ 3V ●───────────┬────────────┬──────────────┐
│ │ │ │ │
│ │ ┌┴┐ ┌┴┐ │
│ │ 10k │ │ 10k │ │ │ (pull-ups
│ │ └┬┘ └┬┘ │ to 3V)
│ │ │ │ │
│ PE9 (CH1) ●───────────┼────────────● A (CLK) │
│ │ │ │ │
│ │ 100n ═╪═ 100n ═╪═ │
│ │ │ │ │
│ PE11 (CH2) ●───────────●────────────┼──● B (DT) │
│ │ │
│ │ ● C (common)──┼──┐
│ │ │ │
│ │ SW1 ●────┘ │
│ PA0 ●──────────────────────────────────● SW2 │ (push-switch, ‖ B1)
│ GND ●──────┬───────────────────────────────────┘
│ │ │ mount legs ●● → GND (shield)
└──────────────┘ │
│ B1 (on-board) also sits 3V ↔ PA0 —
┌─────┴──────┐ the encoder push-switch is in
│ both 100n │ PARALLEL with it.
│ caps → GND │
└────────────┘
```
---
## 3. Breadboard view
```
RC filter — repeat for each channel (A, B):
3V rail ●━━━┯━━━━━━━━━━━┯━━━━● ← from Discovery 3V
│ │
[10k] [10k]
A node ┼───→ PE9 │
B node │ ┼───→ PE11
[100n] [100n]
│ │
GND rail ●━━━┷━━━━━━━━━━━┷━━━━● ← from Discovery GND
EC11 encoder — straddles the centre trench (┊):
┌─────────────────────────────┐
│ A C B ┊ SW1 SW2 │
└──┬────┬────┬───────┬─────┬──┘
│ │ │ │ └───────→ PA0 (SW2 ‖ on-board B1 button)
│ │ │ └─────────────→ 3V rail (SW1)
│ │ └─────────────────────→ B node (DT, channel B → PE11)
│ └──────────────────────────→ GND rail (C = common)
└───────────────────────────────→ A node (CLK, channel A → PE9)
```
Power both breadboard rails from the Discovery's **3V** and **GND** pins; tap
everything else off those rails.
---
## 4. Why the resistors and caps
- **10 kΩ pull-ups (A→3V, B→3V):** *required.* This HAL's QEI driver puts the
pins in alternate-function mode without enabling the internal pull-ups, so the
channels would float. With the encoder common tied to GND, the lines idle high
and each detent pulls them low.
- **100 nF caps (A→GND, B→GND):** *recommended.* Each forms an RC low-pass with
its 10 kΩ pull-up, τ = R·C = 10 kΩ · 100 nF = **1 ms** — long enough to absorb
the ~1–5 ms of mechanical contact bounce, short enough that no hand-turned knob
outruns it. Combined with the STM32 inputs' Schmitt-trigger hysteresis, this
turns each bounced click into one clean edge. The cap's closure surge also
provides wetting current to keep the low-current (~0.3 mA) contacts reliable.
---
## 5. Behaviour (firmware)
- **TIM1 encoder mode** counts quadrature edges (×4). EC11s emit one full cycle
per detent → **4 counter steps per detent** (`COUNTS_PER_DETENT`).
- Each detent moves the setpoint by **`SETPOINT_STEP_C` (1 °C)**, clamped to
**`[SETPOINT_MIN_C, SETPOINT_MAX_C]` = [25, 100] °C**. Power-on default is
**`SETPOINT_DEFAULT_C` = 25 °C**.
- The encoder is sampled every `POLL_MS` (20 ms) in the main poll loops (normal
and fault), so the setpoint tracks smoothly and the per-second status log
prints the live value.
- **Push-switch:** wired in parallel with B1 (3V ↔ PA0). Pressing the knob is
electrically identical to the board button and is handled by the existing PA0
polling — no extra code.
---
## 6. Alternatives
- **Drop the caps:** enable TIM1's built-in digital input filter (sample-count
debounce) in firmware instead. The RC filter is simpler and also gives wetting
current + on-wire noise rejection, so it's preferred for a breadboard build.
- **KY-040 module:** has onboard pull-ups — power it from **3.3 V** (not 5 V) so
CLK/DT/SW idle at a level the MCU pins accept; the external 10 kΩ/100 nF here
can then be omitted.