Skip to content
Martin Mwiti
All documentation

Industrial Valve Controller

Design notes for a dual-channel industrial valve controller with FreeRTOS firmware and CAN integration.

STM32G4FreeRTOSCANKiCadView project

The Story Behind It

Process automation vendors asked for a compact valve driver that could replace ad-hoc relay boards without requiring a full PLC retrofit. Existing options were either overbuilt and expensive, or cheap modules with no diagnostics and no fail-safe story.

The goal was a module an integrator could mount on a DIN rail, wire in an afternoon, and trust for years in a noisy electrical environment.

Requirements

  • Dual independent channels for solenoid or motorized valves
  • Position feedback (analog or digital) per channel
  • Overcurrent and open-load detection
  • CAN 2.0B for PLC / SCADA integration
  • Fail-safe: de-energize actuators on fault or loss of heartbeat
  • 12–24 V industrial supply with reverse polarity protection
  • Operating range: −20 °C to +70 °C
  • Field-updatable firmware over CAN or SWD

Design Process

Architecture started with a risk matrix: what fails, how we detect it, and what the safe state is. That drove MCU selection (STM32G4 for ADCs, timers, and FDCAN), isolation strategy, and task structure.

Schematic capture and layout happened in KiCad with early SPICE checks on the MOSFET drive and current sense path. A first prototype validated power integrity and EMI; a second spin tightened connector pinout and improved thermal vias under the drivers.

Hardware Design

The power stage uses low-Rds(on) N-channel MOSFETs with gate drivers rated for industrial temperatures. Current is sensed with low-side shunts into the STM32 ADC through RC filters tuned for both control bandwidth and noise rejection.

CAN is galvanically isolated. TVS diodes and common-mode chokes sit close to the connector. The board is a 4-layer stackup: signal / GND / power / signal, with continuous ground under high di/dt loops.

typedef struct {
  float position_cmd;
  float position_fb;
  float current_a;
  uint8_t fault_flags;
} valve_channel_t;

Mechanical constraints fixed the enclosure height; connectors and indicators were placed for field serviceability without removing the rail mount.

Firmware Architecture

FreeRTOS hosts four primary tasks:

  1. Control — 1 kHz loop for position/current regulation
  2. Diagnostics — fault aggregation, debounce, and safe-state entry
  3. CAN — TX/RX, heartbeat, object dictionary style registers
  4. Housekeeping — temperature, supply monitor, LED patterns

Shared state lives behind a small lock-free ring for telemetry and a mutex for configuration. Boot performs a self-test of ADCs, drivers (dry-run), and CAN transceiver before enabling outputs.

void control_task(void *arg) {
  TickType_t last = xTaskGetTickCount();
  for (;;) {
    sample_channels();
    run_control_loop();
    update_outputs();
    vTaskDelayUntil(&last, pdMS_TO_TICKS(1));
  }
}

Challenges

EMI from nearby contactors coupled into the current sense path until the shunt filter and layout were revised. CAN error frames under heavy load revealed the need for TX prioritization and a larger RX pool. Thermal rise on continuous solenoid drive required copper pour and thermal vias that the first prototype lacked.

Lessons Learned

  • Define fail-safe behavior before writing application code
  • Isolate early; retrofit isolation is painful
  • Field diagnostics (LEDs, CAN fault codes) pay for themselves on day one
  • Measure current sense noise on the real bus, not just the bench

Future Improvements

  • Optional H-bridge mode for bidirectional motorized valves
  • Web-based commissioning tool over USB-CDC
  • Functional safety documentation path (SIL-oriented design notes)
  • Higher-density connector option for multi-drop racks