Skip to main content

ControlForge + Arduino Uno R4 WiFi: Hardware Interface Guide

James M. Belcher Founder, JMB Technical Services LLC April 2026 | ControlForge v1.0.533


1. Architecture Overview

ControlForge treats the Arduino Uno R4 WiFi as a smart I/O module — not a compilation target. The R4 runs a precompiled firmware (goplc_io.ino, ~99KB compiled) that you upload once via the Arduino IDE or arduino-cli. All hardware control flows through USB CDC serial at 115200 baud using the same binary frame protocol as the Propeller 2 driver.

Unlike the P2 driver's dual-mode interface, the Arduino driver uses a single mode: dedicated ST functions for each capability. There is no generic ARD_CMD — every operation has its own typed function with compile-time parameter checking.

System Diagram


2. Wire Protocol

Every ST function call is packed into a binary frame identical in structure to the P2 protocol:

┌──────┬──────┬─────┬─────┬────────┬──────────────┬────────┐
│ 0xA5 │ 0x5A │ SEQ │ CMD │ LEN(2) │ PAYLOAD(0-N) │ CRC(2) │
│ sync │ sync │ 1B │ 1B │ LE │ LE fields │ MODBUS │
└──────┴──────┴─────┴─────┴────────┴──────────────┴────────┘
  • CRC-16/MODBUS over SEQ + CMD + LEN + PAYLOAD
  • Max payload: 1024 bytes
  • All multi-byte values: little-endian
  • Response uses same frame format
  • USB CDC at 115200 baud (not configurable — firmware default)

You never build frames manually — the ARD_* functions handle packing/unpacking internally.


3. Device Lifecycle

ARD_INIT — Connect to Arduino

Opens the USB CDC serial port and establishes the binary protocol link. The firmware must already be flashed.

ok := ARD_INIT('ard', '/dev/ttyACM0');
ParamTypeDescription
nameSTRINGDevice handle name (used by all other ARD_* calls)
portSTRINGSerial port path

Port Discovery: Use SERIAL_FIND('Arduino') or SERIAL_PORTS() to locate the device automatically. See Section 10.

ARD_STATUS — Connection Health

status := ARD_STATUS('ard');
(* Returns: {"connected":true,"ping_us":312,"board_type":4,
"digital_pins":14,"analog_pins":6,"pwm_pins":6} *)
FieldTypeDescription
connectedboolLink alive
ping_usintRound-trip latency in microseconds
board_typeint0x04 = Arduino Uno R4 WiFi
digital_pinsint14
analog_pinsint6
pwm_pinsint6

ARD_CLOSE — Disconnect

ok := ARD_CLOSE('ard');

Closes the serial port and releases the device handle.

Example: Safe Init with Port Discovery

PROGRAM POU_ArduinoInit
VAR
port : STRING;
ok : BOOL;
status : STRING;
state : INT := 0;
END_VAR

CASE state OF
0: (* Find Arduino *)
port := SERIAL_FIND('Arduino');
IF LEN(port) > 0 THEN
state := 1;
END_IF;

1: (* Connect *)
ok := ARD_INIT('ard', port);
IF ok THEN
state := 2;
END_IF;

2: (* Verify *)
status := ARD_STATUS('ard');
(* Parse board_type — 4 = R4 WiFi *)
state := 10;

10: (* Ready for I/O *)
(* ... *)
END_CASE;
END_PROGRAM

4. Digital I/O

The R4 WiFi has 14 digital pins (D0-D13). D0/D1 are shared with USB serial — avoid using them for GPIO when the serial link is active.

ARD_PIN_MODE — Configure Pin Direction

ParamTypeValues
nameSTRINGDevice handle
pinINT0-13
modeINT0=INPUT, 1=OUTPUT, 2=INPUT_PULLUP
(* Set pin 13 as output (built-in LED) *)
ARD_PIN_MODE('ard', 13, 1);

(* Set pin 2 as input with pull-up *)
ARD_PIN_MODE('ard', 2, 2);

ARD_DIGITAL_READ — Read Digital State

sensor := ARD_DIGITAL_READ('ard', 2);
(* Returns: TRUE or FALSE *)

Note: Returns a native BOOL, not a JSON string. No parsing needed.

ARD_DIGITAL_WRITE — Set Digital Output

ARD_DIGITAL_WRITE('ard', 13, TRUE); (* LED on *)
ARD_DIGITAL_WRITE('ard', 13, FALSE); (* LED off *)

Example: Digital I/O Scan Loop

PROGRAM POU_DigitalIO
VAR
sensor_in : BOOL;
output_on : BOOL;
END_VAR

(* Read sensor on pin 2 (INPUT_PULLUP — active LOW) *)
sensor_in := ARD_DIGITAL_READ('ard', 2);

(* Drive output on pin 13 based on input *)
IF NOT sensor_in THEN
ARD_DIGITAL_WRITE('ard', 13, TRUE);
ELSE
ARD_DIGITAL_WRITE('ard', 13, FALSE);
END_IF;
END_PROGRAM

5. Analog I/O

5.1 Analog Input

The R4 WiFi has 6 analog inputs (A0-A5, mapped to pins 14-19) with a 14-bit ADC (0-16383 range). Reference voltage is 3.3V.

ARD_ANALOG_READ — Read Analog Value

raw := ARD_ANALOG_READ('ard', 14); (* A0 — returns 0-16383 *)
raw := ARD_ANALOG_READ('ard', 15); (* A1 *)
raw := ARD_ANALOG_READ('ard', 19); (* A5 *)
ParamTypeDescription
nameSTRINGDevice handle
pinINT14-19 (A0-A5)

14-bit Resolution: The R4's Renesas RA4M1 provides true 14-bit ADC resolution (0-16383), a significant upgrade over the classic Uno's 10-bit ADC (0-1023). Voltage = raw * 3.3 / 16383.

5.2 PWM Output

6 PWM-capable pins: D3, D5, D6, D9, D10, D11. 16-bit duty resolution (0-65535).

ARD_PWM_WRITE — Set PWM Duty Cycle

(* 50% duty on pin 9 *)
ARD_PWM_WRITE('ard', 9, 32768);

(* Full brightness LED on pin 3 *)
ARD_PWM_WRITE('ard', 3, 65535);

(* Off *)
ARD_PWM_WRITE('ard', 3, 0);
ParamTypeDescription
nameSTRINGDevice handle
pinINTPWM-capable pin (3, 5, 6, 9, 10, 11)
dutyINT0-65535 (16-bit)

5.3 DAC Output

The R4 WiFi has a true 12-bit DAC on pin A0 (pin 14). This outputs a real analog voltage, not PWM.

ARD_DAC_WRITE — Set DAC Value

ARD_DAC_WRITE('ard', 2048); (* ~1.65V — midpoint *)
ARD_DAC_WRITE('ard', 4095); (* ~3.3V — full scale *)
ARD_DAC_WRITE('ard', 0); (* 0V *)
ParamTypeDescription
nameSTRINGDevice handle
valueINT0-4095 (12-bit)

Pin A0 is shared: When using DAC output, A0 cannot simultaneously be used as an analog input. The DAC takes exclusive control of the pin.

Example: Analog Monitor with DAC Feedback

PROGRAM POU_AnalogMonitor
VAR
sensor_raw : INT;
dac_out : INT;
END_VAR

(* Read potentiometer on A1 (pin 15) *)
sensor_raw := ARD_ANALOG_READ('ard', 15);

(* Scale 14-bit input (0-16383) to 12-bit output (0-4095) *)
dac_out := sensor_raw / 4;

(* Mirror input to DAC output on A0 *)
ARD_DAC_WRITE('ard', dac_out);
END_PROGRAM

6. I2C

The R4 WiFi has one hardware I2C bus on the dedicated SDA/SCL pins (next to AREF).

ARD_I2C_SCAN — Scan Bus for Devices

devices := ARD_I2C_SCAN('ard');
(* Returns: "3C,48,68" — comma-separated hex addresses *)
(* Empty string if no devices found *)

ARD_I2C_WRITE_BYTE — Write Single Byte

(* Send command byte 0xAE to OLED at address 0x3C *)
ok := ARD_I2C_WRITE_BYTE('ard', 16#3C, 16#AE);
ParamTypeDescription
nameSTRINGDevice handle
addrINT7-bit I2C device address
valueINTByte to write (0-255)

Example: I2C Device Discovery

PROGRAM POU_I2CScan
VAR
devices : STRING;
state : INT := 0;
END_VAR

CASE state OF
0: (* Scan the bus *)
devices := ARD_I2C_SCAN('ard');
state := 1;

1: (* Check results *)
IF LEN(devices) > 0 THEN
(* Found devices — parse comma-separated hex addresses *)
(* Common: 0x3C=OLED, 0x48=TMP102, 0x68=MPU6050 *)
state := 10;
ELSE
(* No devices — check wiring *)
state := 99;
END_IF;

10: (* Ready to communicate *)
ARD_I2C_WRITE_BYTE('ard', 16#3C, 16#AE); (* OLED display off *)
END_CASE;
END_PROGRAM

7. Servo Control

Up to 4 simultaneous servo channels (indices 0-3). Standard hobby servos with 0-180 degree range.

ARD_SERVO_WRITE — Move Servo

(* Attach servo index 0 to pin 9, move to 90 degrees *)
ARD_SERVO_WRITE('ard', 0, 9, 90);

(* Attach servo index 1 to pin 10, move to 0 degrees *)
ARD_SERVO_WRITE('ard', 1, 10, 0);

(* Move index 0 to 180 degrees (pin remembered from attach) *)
ARD_SERVO_WRITE('ard', 0, 9, 180);
ParamTypeDescription
nameSTRINGDevice handle
idxINTServo index 0-3
pinINTSignal pin
angleINTPosition in degrees (0-180)

Index vs. Pin: The idx parameter is a firmware slot (0-3), not the pin number. Each call specifies both the slot and the pin, so you can reassign slots dynamically. For most applications, assign one index per servo and leave it.

Example: Pan-Tilt Bracket

PROGRAM POU_PanTilt
VAR
pan_angle : INT := 90;
tilt_angle : INT := 90;
step : INT := 1;
state : INT := 0;
END_VAR

CASE state OF
0: (* Initialize — center both servos *)
ARD_SERVO_WRITE('ard', 0, 9, 90); (* Pan on pin 9 *)
ARD_SERVO_WRITE('ard', 1, 10, 90); (* Tilt on pin 10 *)
state := 1;

1: (* Sweep pan left to right *)
pan_angle := pan_angle + step;
IF pan_angle >= 180 THEN
step := -1;
ELSIF pan_angle <= 0 THEN
step := 1;
END_IF;
ARD_SERVO_WRITE('ard', 0, 9, pan_angle);
END_CASE;
END_PROGRAM

8. Sensors

ARD_TEMP_READ — Internal Temperature Sensor

Reads the raw ADC value from the R4's built-in temperature sensor.

raw_temp := ARD_TEMP_READ('ard');
(* Returns: raw ADC value from internal sensor *)
(* Conversion to Celsius is board-specific — see Renesas RA4M1 datasheet *)

ARD_DISTANCE — HC-SR04 Ultrasonic Distance

Measures distance using an HC-SR04 ultrasonic sensor. Returns distance in millimeters. The firmware handles trigger pulse generation and echo timing internally.

dist_mm := ARD_DISTANCE('ard', 7, 8);
(* Returns: distance in millimeters *)
(* 0 or very large value = no echo (out of range or no obstacle) *)
ParamTypeDescription
nameSTRINGDevice handle
trig_pinINTTrigger pin (output)
echo_pinINTEcho pin (input)

Timing Note: The HC-SR04 measurement blocks until the echo returns or times out (~30ms max for ~5m range). This adds latency to the scan cycle. For faster scans, call ARD_DISTANCE on alternating cycles.

Example: Proximity Alert

PROGRAM POU_Proximity
VAR
distance_mm : INT;
alert : BOOL;
led_duty : INT;
END_VAR

(* Measure distance: trigger on D7, echo on D8 *)
distance_mm := ARD_DISTANCE('ard', 7, 8);

(* Alert if closer than 200mm *)
alert := (distance_mm > 0) AND (distance_mm < 200);
ARD_DIGITAL_WRITE('ard', 13, alert);

(* PWM LED brightness inversely proportional to distance *)
IF distance_mm > 0 AND distance_mm < 1000 THEN
led_duty := 65535 - (distance_mm * 65);
IF led_duty < 0 THEN led_duty := 0; END_IF;
ARD_PWM_WRITE('ard', 3, led_duty);
END_IF;
END_PROGRAM

9. WiFi and BLE

The R4 WiFi's ESP32-S3 module provides both WiFi and BLE capabilities.

9.1 WiFi

ARD_WIFI_CONNECT — Join Network

ip := ARD_WIFI_CONNECT('ard', 'MyNetwork', 'MyPassword');
(* Returns: "192.168.1.42" on success, empty string on failure *)
ParamTypeDescription
nameSTRINGDevice handle
ssidSTRINGNetwork name
passwordSTRINGNetwork password

ARD_WIFI_STATUS — Connection Status

wifi := ARD_WIFI_STATUS('ard');
(* Returns: {"Connected":true,"Status":3,"RSSI":-45,"IP":"192.168.1.42"} *)
FieldTypeDescription
ConnectedboolAssociated with AP
StatusintWiFi status code (3=WL_CONNECTED)
RSSIintSignal strength in dBm
IPstringAssigned IP address

9.2 BLE

ARD_BLE_START — Start BLE Advertising

ok := ARD_BLE_START('ard', 'ControlForge-Sensor');
(* Starts BLE peripheral advertising with the given name *)

ARD_BLE_STOP — Stop BLE

ok := ARD_BLE_STOP('ard');

Example: WiFi-Connected Sensor Node

PROGRAM POU_WiFiSensor
VAR
ip : STRING;
wifi_status : STRING;
sensor_val : INT;
state : INT := 0;
END_VAR

CASE state OF
0: (* Connect to WiFi *)
ip := ARD_WIFI_CONNECT('ard', 'PlantFloor', 'SecurePass123');
IF LEN(ip) > 0 THEN
state := 1;
END_IF;

1: (* Verify connection *)
wifi_status := ARD_WIFI_STATUS('ard');
state := 10;

10: (* Running — read sensor and report *)
sensor_val := ARD_ANALOG_READ('ard', 15);
(* WiFi connection enables remote monitoring via ControlForge web UI *)
(* The Arduino's IP can be used for additional TCP/UDP if needed *)
END_CASE;
END_PROGRAM

10. LED Matrix

The R4 WiFi has a built-in 12x8 LED matrix on the board face.

ARD_LED_TEXT — Scroll Text

Scrolls text across the LED matrix. Speed controls the delay between scroll steps.

(* Scroll "Hello" at moderate speed *)
ARD_LED_TEXT('ard', 50, 'Hello');

(* Fast scroll *)
ARD_LED_TEXT('ard', 20, 'ALERT!');

(* Slow scroll for readability *)
ARD_LED_TEXT('ard', 100, 'Temperature: 72F');
ParamTypeDescription
nameSTRINGDevice handle
speedINTMilliseconds per scroll step (lower = faster)
textSTRINGText to scroll

Example: Status Display

PROGRAM POU_StatusDisplay
VAR
distance_mm : INT;
msg : STRING;
scan_count : DINT := 0;
display_interval : DINT := 50; (* Update every ~5s at 100ms scan *)
END_VAR

scan_count := scan_count + 1;

distance_mm := ARD_DISTANCE('ard', 7, 8);

IF (scan_count MOD display_interval) = 0 THEN
msg := CONCAT('Dist: ', INT_TO_STRING(distance_mm), 'mm');
ARD_LED_TEXT('ard', 40, msg);
END_IF;
END_PROGRAM

11. Serial Port Discovery

These functions are shared across all serial-based ControlForge drivers (Arduino, P2, generic serial).

SERIAL_FIND — Find Port by Vendor Name

port := SERIAL_FIND('Arduino');
(* Returns: "/dev/ttyACM0" or empty string if not found *)

(* Also works with partial matches *)
port := SERIAL_FIND('Parallax'); (* Find P2 *)
port := SERIAL_FIND('FTDI'); (* Find FTDI-based device *)

SERIAL_PORTS — List All Serial Ports

ports := SERIAL_PORTS();
(* Returns: JSON array of all detected serial ports *)
(* [{"port":"/dev/ttyACM0","vendor":"Arduino","product":"UNO R4"},
{"port":"/dev/ttyUSB0","vendor":"FTDI","product":"FT232R"}] *)

12. Binary Protocol Command Codes

The Arduino firmware uses command opcodes in the 0xA0-0xB7 range. These are internal to the driver — you never specify them directly — but they are documented here for firmware development and protocol debugging.

Command Table

CommandOpcodeRequest PayloadResponse Payload
Device Lifecycle
ping0xA0
status0xA1connected:u8, ping_us:u32, board_type:u8, digital_pins:u8, analog_pins:u8, pwm_pins:u8
Digital I/O
pin_mode0xA2pin:u8, mode:u8ok:u8
digital_read0xA3pin:u8value:u8
digital_write0xA4pin:u8, value:u8ok:u8
Analog
analog_read0xA5pin:u8value:u16
pwm_write0xA6pin:u8, duty:u16ok:u8
dac_write0xA7value:u16ok:u8
I2C
i2c_scan0xA8count:u8, addrs:bytes
i2c_write_byte0xA9addr:u8, value:u8ok:u8
Servo
servo_write0xAAidx:u8, pin:u8, angle:u8ok:u8
Sensors
temp_read0xABvalue:u16
distance0xACtrig_pin:u8, echo_pin:u8distance_mm:u16
WiFi
wifi_connect0xADssid:string, password:stringip:string
wifi_status0xAEconnected:u8, status:u8, rssi:i16, ip:string
BLE
ble_start0xAFble_name:stringok:u8
ble_stop0xB0ok:u8
LED Matrix
led_text0xB1speed:u16, text:stringok:u8

Frame Examples

Digital Write (pin 13 HIGH):

TX: A5 5A 01 A4 02 00 0D 01 [CRC16]
^^^^^ ^^ ^^ ^^^^^ ^^ ^^
sync seq cmd len=2 pin val

Analog Read (pin 14 / A0):

TX: A5 5A 02 A5 01 00 0E [CRC16]
^^^^^ ^^ ^^ ^^^^^ ^^
sync seq cmd len=1 pin

RX: A5 5A 02 A5 02 00 FF 3F [CRC16]
^^^^^ ^^ ^^ ^^^^^ ^^^^^
sync seq cmd len=2 value=16383 (LE)

13. Complete Example: Sensor Station

A full program combining multiple Arduino peripherals into a sensor monitoring station.

PROGRAM POU_SensorStation
VAR
(* State *)
state : INT := 0;
scan_count : DINT := 0;

(* Device *)
port : STRING;
ok : BOOL;

(* Sensors *)
distance_mm : INT;
light_raw : INT;
temp_raw : INT;

(* Outputs *)
led_duty : INT;
servo_angle : INT;
msg : STRING;
ip : STRING;
END_VAR

CASE state OF
0: (* Discover and connect *)
port := SERIAL_FIND('Arduino');
IF LEN(port) > 0 THEN
ok := ARD_INIT('ard', port);
IF ok THEN
state := 1;
END_IF;
END_IF;

1: (* Configure pins *)
ARD_PIN_MODE('ard', 13, 1); (* LED output *)
ARD_PIN_MODE('ard', 2, 2); (* Button input with pull-up *)
state := 2;

2: (* Connect WiFi *)
ip := ARD_WIFI_CONNECT('ard', 'PlantFloor', 'SecurePass123');
state := 10;

10: (* Main loop — read sensors *)
scan_count := scan_count + 1;

(* Ultrasonic distance *)
distance_mm := ARD_DISTANCE('ard', 7, 8);

(* Light level on A1 *)
light_raw := ARD_ANALOG_READ('ard', 15);

(* Internal temperature *)
temp_raw := ARD_TEMP_READ('ard');

(* Proximity LED — brighter when closer *)
IF distance_mm > 0 AND distance_mm < 1000 THEN
led_duty := 65535 - (distance_mm * 65);
IF led_duty < 0 THEN led_duty := 0; END_IF;
ELSE
led_duty := 0;
END_IF;
ARD_PWM_WRITE('ard', 3, led_duty);

(* Servo tracks distance — closer = more deflection *)
IF distance_mm > 0 AND distance_mm < 2000 THEN
servo_angle := 180 - (distance_mm / 11);
IF servo_angle < 0 THEN servo_angle := 0; END_IF;
ELSE
servo_angle := 0;
END_IF;
ARD_SERVO_WRITE('ard', 0, 9, servo_angle);

(* DAC output proportional to light level *)
ARD_DAC_WRITE('ard', light_raw / 4);

(* Update LED matrix every 5 seconds *)
IF (scan_count MOD 50) = 0 THEN
msg := CONCAT('D:', INT_TO_STRING(distance_mm), 'mm');
ARD_LED_TEXT('ard', 40, msg);
END_IF;

(* Heartbeat *)
ARD_DIGITAL_WRITE('ard', 13, (scan_count MOD 10) < 5);

END_CASE;
END_PROGRAM

14. Hardware Notes for Arduino R4 WiFi Users

Pin Constraints

  • D0/D1: Shared with USB CDC serial. Do not use for GPIO while the ControlForge link is active.
  • A0 (pin 14): Shared between analog input and DAC output. Using ARD_DAC_WRITE claims the pin exclusively.
  • D3, D5, D6, D9, D10, D11: PWM-capable pins. ARD_PWM_WRITE on other pins will fail silently.
  • SDA/SCL: Dedicated I2C pins (next to AREF header). Not remappable.

ADC Resolution

The R4 WiFi uses the Renesas RA4M1 with a true 14-bit ADC. The firmware configures analogReadResolution(14) at boot. Raw values range 0-16383. To convert to voltage:

voltage_mv = raw * 3300 / 16383

PWM Resolution

The firmware configures analogWriteResolution(16) at boot, providing 16-bit duty cycle control (0-65535). Default PWM frequency is ~490 Hz on most pins, ~980 Hz on D5/D6.

DAC Output

The 12-bit DAC on A0 provides true analog voltage output (not PWM-filtered). Output impedance is relatively high — buffer with an op-amp for driving loads. Voltage range is 0-3.3V with 0.8mV resolution (3300/4096).

USB CDC Serial

  • Port: Typically /dev/ttyACM0 on Linux, COM3+ on Windows.
  • Baud: 115200 (fixed in firmware). The ControlForge driver opens at this rate automatically.
  • Reset on connect: Linux DTR assertion resets the Arduino by default. ControlForge suppresses DTR to prevent unwanted resets. If the Arduino resets unexpectedly, check that no other process is opening the port.
  • Latency: USB CDC has ~1ms base latency. Typical round-trip for a command is 2-5ms.

WiFi Module

The ESP32-S3 module handles WiFi and BLE independently from the main RA4M1 MCU. WiFi connection is non-blocking in the firmware — ARD_WIFI_CONNECT waits up to 10 seconds for association. RSSI values below -80 dBm indicate poor signal.

LED Matrix

The 12x8 LED matrix is multiplexed by the firmware. ARD_LED_TEXT initiates a non-blocking scroll — the firmware handles frame updates internally. Sending a new text command while a previous scroll is active replaces it immediately.

Servo Library Limits

The Arduino Servo library supports a maximum of 12 servos, but the ControlForge firmware exposes 4 slots (indices 0-3) to keep command payloads compact. Each ARD_SERVO_WRITE call both attaches the servo to the specified pin and sets the angle. Unlike the P2 driver, there is no interpolation — the servo moves as fast as the hardware allows.

Power

  • USB power: 5V from host, max ~500mA shared across all peripherals.
  • Servo power: Do NOT power servos from the Arduino 5V pin. Use an external supply with common ground.
  • 3.3V logic: All I/O pins are 3.3V on the R4 (unlike the classic Uno's 5V). Most 5V sensors work, but verify logic levels.

15. Arduino vs. Propeller 2 — When to Use Which

CriteriaArduino Uno R4 WiFiPropeller 2
Best forSimple I/O, WiFi/BLE connectivity, quick prototypingHigh pin count, real-time servo/PWM, multi-UART, advanced analog
Digital I/O14 pins64 smart pins
Analog In6 channels, 14-bit4 channels, 14-bit (calibrated mV)
PWM6 channels, 16-bitAny pin, smart pin PWM
DAC1 channel (A0), 12-bitAny pin, 16-bit dithered
UARTUSB only (for ControlForge link)16 channels via smart pins
I2C1 bus (SDA/SCL)8 buses (any pins)
SPINot exposed8 channels
Servo4 channels, no interpolation10 channels, cog-based interpolation
WiFi/BLEBuilt-in (ESP32-S3)None
LED Matrix12x8 built-inNone (OLED via I2C)
Serial speed115200 baud (USB CDC)3 Mbaud (FTDI)
FirmwarePre-flash via Arduino IDEAuto-upload at P2_INIT
Price~$27~$60 (P2-EVAL)
ST interfaceDedicated functions (ARD_*)Generic command (P2_CMD)

Appendix A: Complete Function Quick Reference

FunctionReturnsDescription
ARD_INIT(name, port)BOOLConnect to Arduino over USB serial
ARD_CLOSE(name)BOOLDisconnect and release handle
ARD_STATUS(name)STRINGJSON: connected, ping_us, board_type, pin counts
ARD_PIN_MODE(name, pin, mode)BOOLSet pin direction: 0=IN, 1=OUT, 2=PULLUP
ARD_DIGITAL_READ(name, pin)BOOLRead digital pin state
ARD_DIGITAL_WRITE(name, pin, value)BOOLSet digital output
ARD_ANALOG_READ(name, pin)INTRead analog input (0-16383, 14-bit)
ARD_PWM_WRITE(name, pin, duty)BOOLSet PWM duty (0-65535, 16-bit)
ARD_DAC_WRITE(name, value)BOOLSet DAC output on A0 (0-4095, 12-bit)
ARD_I2C_SCAN(name)STRINGComma-separated hex addresses
ARD_I2C_WRITE_BYTE(name, addr, value)BOOLWrite single byte to I2C device
ARD_SERVO_WRITE(name, idx, pin, angle)BOOLSet servo position (0-180 degrees)
ARD_TEMP_READ(name)INTInternal temperature sensor raw ADC
ARD_DISTANCE(name, trig, echo)INTHC-SR04 distance in millimeters
ARD_WIFI_CONNECT(name, ssid, pass)STRINGJoin WiFi, returns IP or empty
ARD_WIFI_STATUS(name)STRINGJSON: Connected, Status, RSSI, IP
ARD_BLE_START(name, ble_name)BOOLStart BLE advertising
ARD_BLE_STOP(name)BOOLStop BLE
ARD_LED_TEXT(name, speed, text)BOOLScroll text on 12x8 LED matrix
SERIAL_FIND(search)STRINGFind port by vendor name
SERIAL_PORTS()STRINGJSON array of all serial ports

ControlForge v1.0.533 | Firmware: goplc_io.ino (~99KB compiled) | Arduino Uno R4 WiFi @ 48 MHz Protocol: Binary frame (SYNC+SEQ+CMD+LEN+PAYLOAD+CRC16) over USB CDC @ 115200 baud

© 2026 JMB Technical Services LLC. All rights reserved. Back to All Guides