124 lines
3.9 KiB
Markdown
124 lines
3.9 KiB
Markdown
# ptt-fhss
|
||
|
||
Bare-metal PTT (Push-to-Talk) firmware for the **Seeed XIAO BLE (nRF52840)** with
|
||
frequency-hopping spread spectrum (FHSS) on the 2.4 GHz band.
|
||
|
||
Designed to be low-power, hard to detect, and built with a fully open toolchain —
|
||
no Zephyr, no Nordic SDK, no SoftDevice.
|
||
|
||
## Hardware
|
||
|
||
| Component | Part |
|
||
|-----------|------|
|
||
| Target | Seeed XIAO BLE (nRF52840) |
|
||
| Programmer | RP2040 running DAPLink |
|
||
|
||
## How it works
|
||
|
||
### FHSS
|
||
|
||
The radio hops across 40 channels (2402–2480 MHz, 2 MHz steps) every 2 ms.
|
||
The hopping sequence is generated by AES-128-ECB keyed with a shared secret —
|
||
both devices derive identical sequences independently without any synchronisation
|
||
traffic. To an observer with an SDR the transmissions appear as short, scattered
|
||
impulses with no identifiable pattern.
|
||
|
||
### Low power
|
||
|
||
The nRF52840 stays in SYSTEM_ON sleep (`WFI`) with the DC/DC converter active
|
||
(~1.5 µA quiescent). A GPIOTE edge event on the PTT button wakes the CPU;
|
||
the radio is active only during the burst.
|
||
|
||
### Register access
|
||
|
||
All hardware register writes use typed bitfield unions defined in `include/regs.h`
|
||
rather than raw bit-shift expressions. The union layout is guaranteed correct with
|
||
`arm-none-eabi-gcc` (LSB-first bitfields on Cortex-M).
|
||
|
||
## Toolchain
|
||
|
||
Everything that produces the binary runs inside a container. The host only needs
|
||
tools that talk to hardware (pyocd) or manage the build (just).
|
||
|
||
| Tool | Purpose | Install |
|
||
|------|---------|---------|
|
||
| podman or docker | Container runtime | distro package |
|
||
| just | Task runner | `cargo install just` or distro package |
|
||
| pyocd | Flash / debug via DAPLink | `pip install pyocd` |
|
||
| git | Source control + submodules | distro package |
|
||
|
||
Inside the container: `debian:bookworm-slim` + `gcc-arm-none-eabi` from apt +
|
||
`cmake` + `ninja`.
|
||
|
||
## Quick start
|
||
|
||
```sh
|
||
git clone <repo-url> ptt
|
||
cd ptt
|
||
git submodule update --init --depth=1
|
||
|
||
just build # build firmware.hex inside container
|
||
just flash # flash via DAPLink (host pyocd)
|
||
```
|
||
|
||
On first run `just build` pulls the container image and compiles. Subsequent
|
||
builds reuse the cached image and only recompile changed files.
|
||
|
||
## Tasks
|
||
|
||
```
|
||
just build compile firmware inside the container
|
||
just flash build + flash via DAPLink
|
||
just gdbserver start pyocd GDB server on port 3333
|
||
just clean remove build/
|
||
just clean-all remove build/ and the container image
|
||
```
|
||
|
||
## Project structure
|
||
|
||
```
|
||
.
|
||
├── Dockerfile container image (debian + arm-gcc from apt)
|
||
├── justfile build / flash / debug tasks
|
||
├── CMakeLists.txt
|
||
├── cmake/
|
||
│ └── arm-none-eabi.cmake CMake toolchain file
|
||
├── link/
|
||
│ └── nrf52840.ld linker script (no SoftDevice, Flash @ 0x00000000)
|
||
├── include/
|
||
│ ├── regs.h hardware register bitfield unions
|
||
│ ├── radio.h
|
||
│ ├── fhss.h
|
||
│ └── power.h
|
||
├── src/
|
||
│ ├── startup.c vector table (64 entries) + Reset_Handler
|
||
│ ├── main.c
|
||
│ ├── radio.c RADIO peripheral driver (stub)
|
||
│ ├── fhss.c AES-ECB hopping sequence generator
|
||
│ └── power.c DC/DC, GPIOTE wakeup, WFI sleep
|
||
└── vendor/
|
||
├── nrfx/ Nordic HAL headers, pinned to v2.9.0 (includes mdk/)
|
||
├── CMSIS_5/ ARM core headers (core_cm4.h etc.)
|
||
└── tiny-aes-c/ Public domain AES-128 implementation
|
||
```
|
||
|
||
## Before first flash
|
||
|
||
The XIAO BLE ships with a SoftDevice which occupies the start of Flash.
|
||
Erase it before flashing bare-metal firmware:
|
||
|
||
```sh
|
||
pyocd erase --target nrf52840 --chip
|
||
```
|
||
|
||
## Status
|
||
|
||
| Module | State |
|
||
|--------|-------|
|
||
| Startup / vector table | done |
|
||
| Linker script | done |
|
||
| Power management (sleep + wakeup) | done |
|
||
| FHSS sequence generator | done |
|
||
| RADIO driver | stub — TX loop not yet implemented |
|
||
| Sync protocol | not started |
|