wip website docu
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
---
|
||||
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.
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
title: "CAN Bus IDs and Wire Format"
|
||||
date: 2026-05-21
|
||||
draft: false
|
||||
description: "Quick reference for CAN bus identifiers, message formats, and on-the-wire data structures."
|
||||
tags: ["can", "protocol", "wire-format"]
|
||||
---
|
||||
|
||||
# CAN Bus IDs and Wire Format
|
||||
|
||||
A concise technical reference for the PlantCtrl CAN bus protocol.
|
||||
|
||||
## Quick Reference Table
|
||||
|
||||
| CAN ID (hex) | Message Type | Direction | Payload |
|
||||
|--------------|--------------|-----------|----------|
|
||||
| `0x03E8` | Moisture Data - Plant 0, Slot A | Sensor → Controller | u8 plant + u8 slot + u16 hz |
|
||||
| `0x0400` | Identify Command - Plant 0, Slot A | Controller → Sensor | *(empty)* |
|
||||
| `0x042F` | Moisture Data - Plant 15, Slot A | Sensor → Controller | u8 plant + u8 slot + u16 hz |
|
||||
| `0x0467` | Firmware Build - Plant 3, Slot B | Sensor → Controller | u32 build_minutes |
|
||||
|
||||
## ID Calculation Formula
|
||||
|
||||
```
|
||||
ID = 0x03E8 + Message_Offset + Plant_Index (+ Slot_Offset if B)
|
||||
```
|
||||
|
||||
### Constants
|
||||
|
||||
| Constant | Value (hex) | Description |
|
||||
|----------|-------------|-------------|
|
||||
| `SENSOR_BASE_ADDRESS` | `0x03E8` | Base address for all messages |
|
||||
| `MOISTURE_DATA_OFFSET` | `0x00` | Moisture data group |
|
||||
| `IDENTIFY_CMD_OFFSET` | `0x20` | Identify command group |
|
||||
| `FIRMWARE_BUILD_OFFSET` | `0x40` | Firmware build group |
|
||||
| `B_SLOT_OFFSET` | `0x10` | Offset for Slot B within a group |
|
||||
|
||||
### Message Type Offsets
|
||||
|
||||
```rust
|
||||
pub const MOISTURE_DATA_OFFSET: u16 = 0; // sensor → controller
|
||||
pub const IDENTIFY_CMD_OFFSET: u16 = 32; // controller → sensor
|
||||
pub const FIRMWARE_BUILD_OFFSET: u16 = 64; // sensor → controller
|
||||
```
|
||||
|
||||
## On-the-Wire Formats
|
||||
|
||||
### Moisture Data Frame (Sensor → Controller)
|
||||
|
||||
**CAN ID**: `0x03E8 + offset + plant_index` (or `+ 16 + plant_index` for Slot B)
|
||||
|
||||
| Byte | Field | Type |
|
||||
|------|-------|------|
|
||||
| 0 | `plant` | u8 (0–15) |
|
||||
| 1 | `sensor` | SensorSlot (A=0, B=1) |
|
||||
| 2-3 | `hz` | u16 big-endian |
|
||||
|
||||
**Example**: Plant 7, Slot A, frequency 45 Hz
|
||||
```
|
||||
CAN ID: 0x0415
|
||||
Payload: [07 00 00 2D]
|
||||
plant=7, sensor=A, hz=45 (0x002D)
|
||||
```
|
||||
|
||||
### Firmware Build Frame (Sensor → Controller)
|
||||
|
||||
**CAN ID**: `0x03E8 + 64 + plant_index` (or `+ 80 + plant_index` for Slot B)
|
||||
|
||||
| Byte | Field | Type |
|
||||
|------|-------|------|
|
||||
| 0-3 | `build_minutes` | u32 big-endian |
|
||||
|
||||
**Example**: Build timestamp 1,745,239,200 minutes since epoch (May 2026)
|
||||
```
|
||||
CAN ID: 0x0440
|
||||
Payload: [00 00 6A F8]
|
||||
build_minutes = 1,745,239,200
|
||||
```
|
||||
|
||||
### Identify Command Frame (Controller → Sensor)
|
||||
|
||||
**CAN ID**: `0x03E8 + 32 + plant_index` (or `+ 48 + plant_index` for Slot B)
|
||||
|
||||
| Byte | Field | Type |
|
||||
|------|-------|------|
|
||||
| *(none)* | *(empty payload)* | - |
|
||||
|
||||
**Example**: Identify Plant 5, Slot A
|
||||
```
|
||||
CAN ID: 0x0410
|
||||
Payload: (empty)
|
||||
```
|
||||
|
||||
## Addressing Scheme Details
|
||||
|
||||
### Plant Index Range
|
||||
- **Valid**: 0–15 (decimal) or 1–8 on hardware jumpers (mapped internally as 0–7)
|
||||
- **Slot A**: `plant_index` = jumper value - 1
|
||||
- **Slot B**: Same mapping, but ID offset differs by +16
|
||||
|
||||
### Slot Selection
|
||||
| Hardware | Internal Value |
|
||||
|----------|---------------|
|
||||
| Jumper on PA3 (Low) | Slot A (0) |
|
||||
| Jumper on PA3 (High) | Slot B (1) |
|
||||
|
||||
## Error Detection IDs
|
||||
|
||||
The sensor module monitors for unexpected messages:
|
||||
|
||||
- **Moisture Data collision**: If a sensor receives moisture data addressed to itself, it triggers error code 1 (1 info blink, 2 warning blinks)
|
||||
- **CAN errors**: Bus-off, EWGF, EPVF flags trigger warning LED blinking
|
||||
|
||||
## Protocol Extensions
|
||||
|
||||
To add new message types:
|
||||
|
||||
1. Define offset in `canapi/src/lib.rs`:
|
||||
```rust
|
||||
pub const NEW_MESSAGE_OFFSET: u16 = 96; // Next available slot
|
||||
```
|
||||
|
||||
2. Implement message struct with bincode serialization
|
||||
3. Add receive handler on both sides
|
||||
4. Update documentation
|
||||
|
||||
## Binary Protocol Reference
|
||||
|
||||
### bincode v2 Serialization
|
||||
- **u8**: Single byte, no sign extension
|
||||
- **u16**: 2 bytes big-endian (network order)
|
||||
- **u32**: 4 bytes big-endian (network order)
|
||||
- No varints – fixed size for predictable CAN frame lengths
|
||||
|
||||
### CAN Frame Structure
|
||||
```
|
||||
| Arbitration Field | Control Field | Data Field (8 bytes) |
|
||||
|-------------------|---------------|----------------------|
|
||||
| 11-bit ID | RTR + IDE | Payload (max 4-6 bytes)|
|
||||
```
|
||||
|
||||
All PlantCtrl messages fit within the 8-byte data field with room for CAN overhead.
|
||||
Reference in New Issue
Block a user