STM32F446RE-based LoRa sensor network with binary serialization, CRC integrity checking, and reliable transmission state machine.
This repository builds on Week 2's text-based LoRa communication to implement a production-grade binary protocol with:
- Postcard serialization for efficient binary encoding
- CRC-16 integrity checking for data validation
- ACK/retry state machine for reliable delivery
- Sequence number tracking for duplicate detection
- Performance comparison between text and binary protocols
Payload: "T:27.1H:56.0G:74721#0003" (24 bytes)
AT Command: "AT+SEND=2,24,T:27.1H:56.0G:74721#0003" (39 bytes total)
No integrity checking, no acknowledgments, no retries
Payload: Binary struct (12-16 bytes) + CRC-16 (2 bytes)
Transmission: Automatic retries on failure
Reception: ACK sent back to transmitter
Integrity: CRC validation on every packet
Efficiency: ~40% size reduction vs text
Same dual-node setup from Week 2:
- MCU: STM32F446RET6 (Cortex-M4F @ 84 MHz, HSI clock)
- Board: NUCLEO-F446RE
- Radio: REYAX RYLR998 LoRa Module (UART4 @ 115200 baud)
- Primary Sensor: SHT31-D (Temperature & Humidity - Golden Reference)
- Secondary Sensor: BME680 (Gas Resistance, Temperature, Humidity, Pressure)
- Display: SSD1306 OLED 128x64 I2C
- Power: Split-rail (Elegoo MB102 for LoRa, Nucleo for Logic)
- Debug: LED on PA5
- ST-Link Probe:
0483:374b:0671FF3833554B3043164817
- MCU: STM32F446RET6 (Cortex-M4F @ 84 MHz, HSI clock)
- Board: NUCLEO-F446RE
- Radio: REYAX RYLR998 LoRa Module (UART4 @ 115200 baud)
- Sensor: BMP280 (Temperature & Pressure - local reference)
- Display: SSD1306 OLED 128x64 I2C
- Power: USB-powered via ST-Link
- Debug: LED on PA5
- ST-Link Probe:
0483:374b:066DFF3833584B3043115433
| Peripheral | Protocol | Pin(s) | Function |
|---|---|---|---|
| LED | GPIO | PA5 | Status indicator (toggles @ 1 Hz) |
| I2C1 SCL | I2C | PB8 | Sensor & Display bus clock |
| I2C1 SDA | I2C | PB9 | Sensor & Display bus data |
| UART4 TX | UART | PC10 | LoRa module transmit |
| UART4 RX | UART | PC11 | LoRa module receive |
- Define message types (Data, ACK, NACK)
- Create Serde-compatible structs
- Implement CRC-16 calculation
- Design packet framing format
- Integrate postcard serialization
- Test serialization/deserialization on desktop
- Port to embedded (no_std)
- Measure serialized payload sizes
- Design TX state machine (Idle → Sending → WaitACK → Retry/Success)
- Design RX state machine (Listen → Validate → SendACK)
- Implement timeout handling
- Add retry logic with backoff
- Replace text protocol with binary in Node 1
- Replace text parsing with binary in Node 2
- End-to-end testing
- Measure packet success rate
- Compare payload sizes (text vs binary)
- Measure round-trip latency
- Test retry behavior with packet loss
- Document efficiency gains
- Handle duplicate packets (sequence numbers)
- Test boundary conditions
- Optimize buffer sizes
- Add comprehensive logging
- Performance comparison report
- Update PROTOCOL.md with binary format spec
- Complete NOTES.md with learnings
- Week 3 review and planning for Week 4
Binary Protocol Efficiency:
- Payload Size: 10 bytes (8 data + 2 CRC) vs 25 bytes text = 60% reduction
- Round-trip Latency: <1 second (observed in successful transmissions)
- Timeout Behavior: 2s × 3 attempts = 6 seconds total before giving up
- Success Rate: 70-80% in real-world conditions (64+ packets tested)
State Machine Validation:
- ✅ Graceful timeout handling with configurable retry count (MAX_RETRIES = 3)
- ✅ Automatic recovery when network conditions improve
- ✅ No crashes or hangs on repeated failures
- ✅ Clean state transitions (Idle ↔ WaitingForAck)
Real-World Testing:
- Tested with natural packet loss (packets #3, #4, #10, #13 failed during extended run)
- System continued operating through failures
- Immediate recovery on successful ACK reception
- CRC validation: 100% of received packets validated successfully
Range Test Results (2025-12-27):
| Distance | RSSI | SNR | Success Rate | Environment |
|---|---|---|---|---|
| 15m | -45 dBm | 13 dB | 100% | Through walls, no LoS |
| 30m | -62 dBm | 13 dB | 99% | Wall obstacles |
| 60m | -72 dBm | 12 dB | 99% | Wall obstacles |
| 100m | -82 dBm | 11 dB | 99% | Downhill, trees, no LoS |
| 150m | -91 dBm | 4 dB | 98% | Buildings & trees, no LoS |
| 400m | -100 dBm | -2 dB | 98% | Buildings & trees, no LoS |
| 600m | -107 dBm | -6 dB | 95% | Buildings & trees, no LoS |
Key Findings:
- ✅ 600m range achieved through suburban obstacles (no line of sight)
- ✅ 95% success rate at 600m near LoRa sensitivity limit (-107 dBm)
- ✅ >98% success rate up to 400m even with negative SNR
- ✅ LoRa spread spectrum works below noise floor (functional at -6 dB SNR)
- ✅ Predictable signal degradation (~10 dBm per doubling of distance)
Range Test Visualization:
Graph shows RSSI, SNR, and packet loss vs distance. Generate with python3 plot_range_test.py
Week 3 Status: ✅ COMPLETE - All core objectives achieved, binary protocol operational with reliable delivery state machine, 600m range validated.
cargo build --releasecargo build --release --bin node2cargo build --release && probe-rs run --probe 0483:374b:0671FF3833554B3043164817 --chip STM32F446RETx target/thumbv7em-none-eabihf/release/wk3-binary-protocolcargo build --release --bin node2 && probe-rs run --probe 0483:374b:066DFF3833584B3043115433 --chip STM32F446RETx target/thumbv7em-none-eabihf/release/node2# Node 1
alias n1='cargo build --release && probe-rs run --probe 0483:374b:0671FF3833554B3043164817 --chip STM32F446RETx target/thumbv7em-none-eabihf/release/wk3-binary-protocol'
# Node 2
alias n2='cargo build --release --bin node2 && probe-rs run --probe 0483:374b:066DFF3833584B3043115433 --chip STM32F446RETx target/thumbv7em-none-eabihf/release/node2'#[derive(Serialize, Deserialize, Debug)]
pub enum MessageType {
SensorData,
Ack,
Nack,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct SensorDataPacket {
pub seq_num: u16,
pub temperature: i16, // Centidegrees (e.g., 2710 = 27.1°C)
pub humidity: u16, // Basis points (e.g., 5600 = 56.0%)
pub gas_resistance: u32,
pub crc: u16,
}[Length (1 byte)][Message Type (1 byte)][Payload (N bytes)][CRC-16 (2 bytes)]
Example SensorDataPacket:
- Length: 1 byte (e.g., 14)
- Type: 1 byte (0x01 = SensorData)
- Sequence: 2 bytes (u16)
- Temperature: 2 bytes (i16)
- Humidity: 2 bytes (u16)
- Gas: 4 bytes (u32)
- CRC: 2 bytes (u16)
- Total: ~14 bytes vs 24 bytes text
Key crates:
stm32f4xx-hal = "0.23.0"- Hardware abstraction layercortex-m-rtic = "1.1"- RTIC frameworkserde = "1.0"- Serialization framework (no_std)postcard = "1.0"- Binary serialization formatcrc = "3.0"- CRC calculationsht3x = "0.1.1"- SHT31 sensor driverbme680 = "0.6.0"- BME680 sensor driverssd1306 = "0.8.4"- OLED display drivershared-bus = "0.3.1"- I2C bus sharingheapless = "0.8"- Stack-allocated data structuresdefmt-rtt = "0.4"- Logging via RTT
See Cargo.toml for complete dependency list.
wk3-binary-protocol/
├── src/
│ ├── main.rs # Node 1 firmware (binary TX)
│ └── bin/
│ └── node2.rs # Node 2 firmware (binary RX)
├── Cargo.toml # Dependencies with Week 3 additions
├── memory.x # Linker script for STM32F446
├── README.md # This file
├── NOTES.md # Learning insights
├── TROUBLESHOOTING.md # Issues and solutions
└── PROTOCOL.md # Binary protocol specification
Week 3 Complete When:
- Binary protocol replaces text protocol
- CRC validation working on every packet
- ACK/NACK mechanism implemented
- Retry logic handles packet loss gracefully
- Sequence numbers prevent duplicate processing
- Performance comparison documented
- Payload size reduced by >30% vs text
- Packet delivery rate >95% (maintained from Week 2)
This repository starts with the working Week 2 codebase:
- ✅ Multi-sensor integration (BME680 + SHT31-D)
- ✅ Shared I2C bus with mutex management
- ✅ OLED display with sensor data
- ✅ LoRa transmission working end-to-end
- ✅ RTIC timing patterns established
- ✅ Simple, reliable UART interrupt handlers
Week 2 Achievement: Text-based LoRa communication with 100% packet delivery at close range, RSSI -20 to -22 dBm, SNR 13 dB.
Week 3 Goal: Same reliability with binary protocol, adding integrity checking and automatic retries.
- Postcard Documentation: https://docs.rs/postcard/
- Serde no_std Guide: https://serde.rs/no-std.html
- CRC Theory: https://en.wikipedia.org/wiki/Cyclic_redundancy_check
- State Machine Patterns in Embedded Rust
- RTIC Shared Resources (from Week 2)
- Week 2 Repository: wk2-lora-sensor-fusion
- Overall Plan: 4-Month Plan
- Weekly Details: PLAN_WEEKLY.md
Author: Antony (Tony) Mapfumo Part of the 12-Week IIoT Systems Engineer Transition Plan Week 3 of 12 - Binary Protocol & State Machine
