195 lines
7.0 KiB
Markdown
195 lines
7.0 KiB
Markdown
---
|
||
title: "CAN Bus Protocol"
|
||
date: 2026-05-21
|
||
draft: false
|
||
description: "Complete documentation of the CAN bus communication protocol between PlantCtrl sensor modules and main controller."
|
||
tags: ["can", "protocol", "sensor"]
|
||
---
|
||
|
||
# CAN Bus Protocol
|
||
|
||
The PlantCtrl system uses a custom **CAN bus-based communication protocol** to connect sensor modules (moisture sensors) with the MainBoard controller. This modular design allows for scalable, reliable digital communication even over long cable runs and in electrically noisy environments.
|
||
|
||
## Overview
|
||
|
||
- **Protocol**: Standard CAN 2.0A (11-bit identifier)
|
||
- **Baud Rate**: 50 kbps
|
||
- **Base Address**: `0x03E8` (decimal 1000)
|
||
- **Maximum Plants**: 16 per sensor module
|
||
- **Sensors per Plant**: 2 slots (A and B) for redundancy or larger planters
|
||
|
||
## CAN Bus IDs
|
||
|
||
All messages use the standard base address `0x03E8` with message-specific offsets. The ID structure is:
|
||
|
||
```
|
||
ID = 0x03E8 + Message_Offset + Plant_Index (+ Slot_Offset if B)
|
||
```
|
||
|
||
### Message Groups
|
||
|
||
| Group | Offset (hex) | Direction | Description |
|
||
|-------|--------------|-----------|-------------|
|
||
| Moisture Data | `0x00` | Sensor → Controller | Periodic moisture readings |
|
||
| Identify Command | `0x20` | Controller → Sensor | LED identification command |
|
||
| Firmware Build | `0x40` | Sensor → Controller | Compile-time build timestamp |
|
||
|
||
### Plant Addressing (Slots A & B)
|
||
|
||
Each plant gets two sensor slots:
|
||
- **Slot A**: Base offset + plant index (0–15)
|
||
- **Slot B**: Base offset + 16 + plant index (0–15)
|
||
|
||
#### Example ID Calculations
|
||
|
||
| Message Type | Plant | Slot | CAN ID (hex) |
|
||
|--------------|-------|------|-------------|
|
||
| Moisture Data | 0 | A | `0x03E8` |
|
||
| Moisture Data | 7 | A | `0x0415` |
|
||
| Moisture Data | 15 | A | `0x042F` |
|
||
| Identify Command | 0 | A | `0x0400` |
|
||
| Firmware Build | 3 | B | `0x0467` |
|
||
|
||
## Message Formats
|
||
|
||
All messages are serialized using **bincode v2** (fixed-size integers, no varints). Each message fits within a single CAN frame.
|
||
|
||
### Moisture Data (Sensor → Controller)
|
||
|
||
Sent periodically by each sensor module. Contains:
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `plant` | u8 | Plant index (0–15) |
|
||
| `sensor` | SensorSlot | A or B slot |
|
||
| `hz` | u16 | Measured frequency in Hz |
|
||
|
||
**Total size**: 4 bytes (fits easily in CAN frame)
|
||
|
||
### Identify Command (Controller → Sensor)
|
||
|
||
Sent by the controller to trigger an LED identification sequence on the sensor module.
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| *(empty)* | - | No payload data |
|
||
|
||
**Purpose**: When received, the sensor blinks its status LED for a few seconds to confirm it's online and properly configured.
|
||
|
||
### Firmware Build (Sensor → Controller)
|
||
|
||
Sent immediately after receiving an Identify Command. Contains:
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `build_minutes` | u32 | Compile-time timestamp in minutes since Unix epoch |
|
||
|
||
**Purpose**: Allows the controller to track firmware versions and deployment history without requiring a separate request.
|
||
|
||
## Sensor Configuration
|
||
|
||
Each sensor module is configured via **hardware jumpers** on startup. The configuration is read by the CH32V203 MCU and determines:
|
||
- Whether it's Slot A or B for a plant
|
||
- The plant index (1–8)
|
||
|
||
### Hardware Switches
|
||
|
||
| Pin | Function |
|
||
|-----|----------|
|
||
| PA3 | **Slot selector**: Low = A, High = B |
|
||
| PA4 | Address bit 1 (value: 1) |
|
||
| PA5 | Address bit 2 (value: 2) |
|
||
| PA6 | Address bit 3 (value: 4) |
|
||
| PA7 | Address bit 4 (value: 8) |
|
||
|
||
### Valid Addresses
|
||
|
||
- **Allowed**: 1–8 (binary combinations of bits 1,2,4,8)
|
||
- **Invalid**: 0 or >8 (will trigger error code)
|
||
|
||
#### Example Configurations
|
||
|
||
| Address | Binary | Jumpers |
|
||
|---------|--------|----------|
|
||
| 1 | `0001` | PA4 only |
|
||
| 3 | `0011` | PA4 + PA5 |
|
||
| 7 | `0111` | PA4 + PA5 + PA6 |
|
||
| 8 | `1000` | PA7 only |
|
||
|
||
## Error Detection & Blink Codes
|
||
|
||
The sensor module performs **floating pin detection** at startup. If any configuration pin is left floating (not connected to VCC or GND), the system enters an error state and blinks a diagnostic code.
|
||
|
||
### Error Code Table
|
||
|
||
| Code | Cause | LED Pattern |
|
||
|------|-------|-------------|
|
||
| 1 | PB4 floating (bit 1) | 1 blink info, 2 blinks warning |
|
||
| 2 | PB5 floating (bit 2) | 2 blinks info, 2 blinks warning |
|
||
| 3 | PB6 floating (bit 3) | 3 blinks info, 2 blinks warning |
|
||
| 4 | PB7 floating (bit 4) | 4 blinks info, 2 blinks warning |
|
||
| 5 | PB3 floating (A/B selector) | 5 blinks info, 2 blinks warning |
|
||
| 6 | Invalid address (0 or >8) | 6 blinks info, 2 blinks warning |
|
||
|
||
### LED Indicators
|
||
|
||
- **Info LED** (PA10): Green – indicates information state
|
||
- **Warning LED** (PA9): Yellow/Orange – indicates error/warning state
|
||
|
||
The blink pattern repeats 5 times, then the system resets automatically.
|
||
|
||
## Address Collision Detection
|
||
|
||
The protocol includes built-in collision detection. If a sensor receives a moisture data packet addressed to itself, it triggers an error sequence:
|
||
- **Blink code**: 1 info blink, 2 warning blinks
|
||
- **Log message**: "We should never receive moisture packets addressed to ourselves"
|
||
|
||
This indicates another node is using the same jumper configuration.
|
||
|
||
## CAN Bus Robustness Features
|
||
|
||
The firmware implements several features for reliable operation:
|
||
|
||
### Automatic Retransmission (NART)
|
||
Enabled on the CH32V203 CAN controller to recover from transient errors without manual intervention.
|
||
|
||
### Resync Jump Width (SJW = 4TQ)
|
||
Increased from default (1TQ) to improve jitter tolerance over long cable runs. This allows the receiver to resynchronize with the bit stream even if timing drifts slightly.
|
||
|
||
### Error Status Monitoring
|
||
The controller monitors CAN error registers for:
|
||
- Bus-off condition (`BOFF`)
|
||
- Error warning flag (`EWGF`)
|
||
- Error passive flag (`EPVF`)
|
||
|
||
When errors are detected, warning LEDs blink and the system logs the status.
|
||
|
||
## Troubleshooting
|
||
|
||
### Sensor Not Detected
|
||
1. Check all jumpers – ensure no floating pins
|
||
2. Verify address is 1–8 (not 0 or >8)
|
||
3. Confirm slot selector (A/B) matches expected configuration
|
||
4. Listen for CAN traffic with a CAN analyzer
|
||
5. Check error blink codes on the sensor module
|
||
|
||
### Address Collision
|
||
- Two sensors using identical jumper settings will cause collisions
|
||
- Use the collision detection feature to identify duplicate addresses
|
||
- Reconfigure one of the conflicting sensors to a different address
|
||
|
||
### Communication Errors
|
||
- **Bus-off**: Check CAN termination resistors (120Ω at each end)
|
||
- **High error rate**: Verify cable quality and shielding
|
||
- **Intermittent errors**: Check for electrical noise from pumps or motors
|
||
|
||
## Future Extensions
|
||
|
||
The protocol is designed to be extensible. New message types can be added by:
|
||
1. Defining a new offset in `canapi/src/lib.rs`
|
||
2. Implementing the corresponding message struct with bincode serialization
|
||
3. Adding receive handlers on both sensor and controller sides
|
||
4. Documenting the new ID range and format
|
||
|
||
The current design supports up to 64 distinct message types (16 plants × 2 slots × 2 directions) while maintaining a clean, plant-indexed addressing scheme.
|