4.0 KiB
4.0 KiB
SCD30 HIL Framework Documentation
1. System Architecture
The system consists of three layers. The PC handles the Logic, the Emulator handles the Signal Bridge, and the Target runs the Production Code.
graph TD
subgraph "PC (Python)"
A[Global Test Script] <--> B[HIL Library]
end
subgraph "Emulator ESP32 (Slave)"
C[UART Driver] <--> D[I2C Slave Driver]
end
subgraph "Target ESP32 (Master)"
E[SCD30 Driver Component] <--> F[Application Logic]
end
B <-- "921600 Baud Serial" --> C
D <-- "I2C Bus (Clock Stretching)" --> E
2. The Logic Workflow (Sequence)
This is the most critical part: how we synchronize a slow PC with a fast I2C bus.
sequenceDiagram
participant PC as Python (Global Script)
participant Slave as ESP32 Emulator (Slave)
participant Master as ESP32 Target (Master)
Note over Master: App calls scd30_read_data()
Master->>Slave: I2C Write: [0x03, 0x00] (Read Cmd)
activate Slave
Slave->>PC: UART Send: "CMD:0300\n"
Note right of Slave: Slave STRETCHES Clock (SCL LOW)
Note over PC: Lib parses CMD, calculates<br/>Floats & CRCs
PC->>Slave: UART Send: "DATA:010203...\n"
Slave->>Slave: Parse Hex to Bytes
Slave->>Master: Load I2C Buffer & Release SCL
deactivate Slave
Master->>Slave: I2C Read: 18 Bytes
Note over Master: App parses bytes to Float
Master->>PC: UART Print: "CO2: 450.00..."
Note over PC: Global script captures & logs to CSV
3. Component Breakdown
A. Target ESP32 (scd30.c)
- Role: Acts as the I2C Master. It believes it is talking to a real SCD30.
- Key Logic: * Initialization: Configures
scl_wait_us = 150000. This is the timeout for how long it will wait while the Slave is stretching the clock. - Parsing: Takes 18 bytes and reconstructs three 32-bit floats. It skips every 3rd byte because that is the CRC.
- Polling: It continuously asks "Are you ready?" (0x0202) until the Emulator (PC) replies with "Yes" (0x01).
B. Emulator ESP32 (main.c)
- Role: The "Transparent Bridge."
- Key Logic:
- Event-Driven: Uses a callback (
on_recv_done) to notify a task that the Master has sent a command. - Clock Stretching: By not loading the TX buffer immediately, the hardware automatically holds the SCL line low. This pauses the Master's CPU.
- Synchronization: It bridges the I2C domain (microseconds) to the PC domain (milliseconds).
C. Python Library (hil_lib.py)
- Role: The "Sensor Physics Engine."
- Key Logic:
- SCD30 Protocol Emulation: It knows that if the Master sends
0202, it must reply with000103(Ready). - Data Formatting: Converts human-readable numbers (like
450.0) into the raw hex bytes and CRCs the ESP32 expects.
D. Global Script (run_test.py)
- Role: The "Test Orchestrator."
- Key Logic:
- Iteration: Loops through a list of test values.
- Verification: It acts as a "Man-in-the-Middle." It knows what value it sent to the sensor and reads the Target's serial to see what value the Target received.
- Persistence: Saves the input/output pair into a
.csvfor audit and validation.
4. Hardware Connectivity
| Connection | Requirement | Why? |
|---|---|---|
| SDA to SDA | 4.7kΩ Pull-up to 3.3V | Data signal integrity |
| SCL to SCL | 4.7kΩ Pull-up to 3.3V | Clock signal integrity |
| GND to GND | Solid Copper Wire | Reference voltage for signals |
| UART 0 | USB Cable to PC | Command/Data bridge |
5. Troubleshooting the Workflow
-
Symptom: Target says
Failed to read data. -
Cause: Python script took longer than 200ms to respond OR
scl_wait_usis too low. -
Symptom: Target reads
0.00. -
Cause: The CRC check failed in the C code, or the Python script sent the bytes in the wrong order.
-
Symptom: CSV only has Column 1, not Column 2.
-
Cause: The Target ESP32 is not printing to the correct Serial port, or the baud rate is mismatched.