A high-performance system for real-time waveform generation and processing using a dual-CPU architecture (CPU1 for acquisition, CPU2 for packet generation). This project includes an embedded C core and Python-based visualization tools.
- Dual-CPU Logic: Optimized shared-memory communication between acquisition and processing cores.
- Real-time Server: Python-based server for data recovery and distribution.
- Interactive Visualizer: Multi-channel waveform viewer with historical data support.
- Simulation Mode: Robust Windows-based simulation environment for development and testing.
src/: Core implementation.dual_cpu_logic.c: Standard embedded C implementation.dual_cpu_logic_irq.c: Alternative IRQ-based implementation.waveform_server.py: TCP server for device communication.plot_gui.py: Interactive Tkinter visualizer.
docs/: Technical design specifications and documentation.data/: Sample datasets and simulation logs.log/: Runtime logs (generated during simulation).
- Python 3.8+
- C Compiler (for embedded builds or simulation)
- Dependencies:
pip install -r requirements.txt
- Start the Server:
python src/waveform_server.py
- Launch the Visualizer:
python src/plot_gui.py
The core design utilizes a producer-consumer pattern implemented across two CPUs (CPU1 and CPU2) communicating via shared memory. This approach decouples the high-frequency, real-time sample acquisition on CPU1 from the more complex, event-driven packet processing and submission handled by CPU2.
- CPU1 (Producer): Acquires 32 channels of sample data every 100µs. Its primary role is to efficiently write these samples along with a timestamp into a shared ring buffer.
- CPU2 (Consumer): Operates on a polled basis (100µs - 2ms interval). It consumes data from the shared buffer based on signals from CPU1 and external demands. CPU2 manages waveform packet assembly (500 samples), buffering, and rate-limited submission to the external environment.
- Communication: A shared ring buffer in the 64KB shared RAM is the main conduit for sample data transfer. Synchronization relies on volatile flags (
shared_newDataBlockReady) and indices managed by CPU1 and read by CPU2, coordinated with memory barriers. CPU2 uses internal queues (cpu2_waveforNewDemandCommandQueue,cpu2_waveformPacketInfoQueue) to manage incoming demands and outgoing packets, decoupling processing steps.
While the provided implementation is configured for a specific 64KB shared RAM footprint and 32-channel acquisition, the architecture is designed to be highly scalable. All core parameters—including channel counts, buffer sizes, sample rates, and packet lengths—are defined via constants and can be adjusted to suit different hardware architectures:
- Memory Footprint: Shared RAM usage can be reduced or expanded by adjusting
SHARED_BUFFER_SLICES. - Performance Tuning: Throughput can be optimized by tuning
SHARED_BUFFER_BLOCK_SIZEandSHARED_MAX_WAVESUBMIT_DELAY_US. - Channel Scalability: The system supports increasing the number of active channels or processing slots depending on the available CPU overhead and bandwidth.
Full technical specifications and architectural deep-dives are available upon request to promote engagement. Please contact the author at info@intellugo.com for the detailed Design Overview PDF.
This project is licensed under the MIT License - see the LICENSE file for details.
Intellugo Engineering (info@intellugo.com)
