Skip to content

System Architecture

The technical detail behind the block diagram on Workflow Integration. Same system, same signal path — this page names the actual cores, protocols and timings.

LoopCheck sits between the host PC running the test suite and the Device Under Test. The board simulates the DUT's peripheral environment in real time; the host only defines what to test, not when each edge happens. That split is why timing assertions are deterministic — the microsecond-level work never depends on host or network latency.

The central idea: your test logic runs in C on the board itself, in real time, and you orchestrate it from Python. You are not sending individual commands over the network and hoping the timing holds — you write the time-critical behavior as C code that executes on a dedicated core, and use Python to start sequences, set variables, and read back results.

flowchart TD
    subgraph HOST["Host PC / Server"]
        TEST["Test framework<br/>(Behave, pytest, …)"]
        API["Python LoopCheck API"]
        TEST --> API
    end

    API <-->|"UDP :28000"| CM

    subgraph BOARD["LoopCheck Board"]
        CM["CM core<br/>Logging and automation<br/>(network bridge)"]
        CPU2["CPU2<br/><b>Your C code</b><br/>Test logic / simulation model"]
        CPU1["CPU1<br/>Hardware abstraction<br/>Real-time and analog"]
        CM <--> CPU2
        CPU2 <-->|"Shared memory<br/>C API"| CPU1
    end

    CPU1 <--> ADAPTER

    ADAPTER["Adapter Board<br/>(Docking Shield)"]

    ADAPTER <--> DUT

    DUT["Device Under Test"]

Firmware Architecture

The F2838x multi-core architecture lets each core do one job, so real-time behavior is never blocked by communication or logging.

CPU2 — your test logic

CPU2 runs your custom C code: the test logic, or a simulation model of the DUT's environment. This is the core you program.

  • Executes complete test sequences in real time, on the board, without host involvement
  • Calls the hardware abstraction API to set signals, read inputs and drive communication — it does not touch registers or pins directly
  • Communicates with CPU1 over shared memory
  • Exposes variables that the Python API can read and write from the host

Because the logic lives here rather than on the host, sequences with microsecond-level timing requirements stay deterministic regardless of network or PC load.

Standard C development, not a proprietary environment

CPU2 is programmed like any other embedded target. You write ordinary C against the TI C2000 SDK (C2000Ware) and build, flash and run it from Code Composer Studio (CCS VS Code) over USB — the same toolchain a firmware engineer already uses for a C2000 project. There is no proprietary language or bespoke IDE to learn; the hardware abstraction API is just a set of C functions on top of the SDK.

On-chip debugging of the test environment

Because CCS talks to the device over the on-chip debug probe, you get full on-chip debugging of your test logic: breakpoints, single-stepping, and live inspection or modification of variables while a run is in progress. This makes it fast to analyze a failing test run and fix issues in the test environment itself — you debug the simulation model or test logic directly on the core it runs on, instead of inferring what happened from logs after the fact.

CPU1 — hardware abstraction

CPU1 provides the hardware abstraction layer and owns everything real-time and analog:

  • Peripheral simulation: Specialized simulators such as encoder emulation
  • Analog and real-time communication: Drives digital signals to the DUT and monitors DUT outputs
  • Hardware timestamping: All events (signal transitions, command receipts) are timestamped at 0.1 µs resolution for precise timing verification
  • Abstraction: Presents a clean C API to CPU2, so test logic works in terms of named signals rather than pin numbers and registers

This is the layer that gets adapted when the target changes — see Adapting to a New DUT.

CM — logging and automation

The ARM Cortex-M4 Connectivity Manager handles logging and automation, and serves as the network bridge to the host:

  • UDP command interface (Port 28000): Receives commands from the host PC and routes them to the C code on CPU2
  • Log streaming: Reads completed log buffers from shared memory and transmits them to the host
  • START/STOP commands control the log capture window

Communication paths

Path Mechanism
Host PC ↔ CPU2 12-byte command packets (3× uint32) over UDP, routed by the CM core
CPU2 ↔ CPU1 Shared memory, through the hardware abstraction C API
CPU1/CPU2 → Host Log buffers in shared memory; CM reads and sends them via UDP

Why this split matters

A purely host-driven HIL system is limited by network round-trip time — typically hundreds of microseconds, and not deterministic. By putting the test logic on CPU2 and the hardware abstraction on CPU1, LoopCheck keeps the timing-critical loop entirely on the board. Python then does what it is good at: orchestration, parameterization and reporting.

Orchestrating your C code from Python