125 lines
4.0 KiB
Markdown
125 lines
4.0 KiB
Markdown
|
|
# 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**.
|
|
|
|
```mermaid
|
|
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.
|
|
|
|
```mermaid
|
|
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 with `000103` (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 `.csv` for 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_us` is 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.
|
|
|