Resolving SIMATIC IOT2050 Digital Input Read Failures
When a SIMATIC IOT2050 (Basic or Advanced) is paired with the Siemens I/O Shield and read attempts through mraa-gpio or Node-RED return a constant 0 regardless of the 24 V DC applied to DI0/DI1, the root cause is almost always one of three configuration errors: the M0 (ground) reference is not wired, the on-board function select is set to something other than DI/DQ, or the wrong GPIO pin number is being polled. This reference walks through pin mapping, the iot2050setup tool, the mraa-gpio CLI, and Node-RED verification so the inputs read correctly in production.
mraa-gpio get 12 reliably returns 0 until M0 is bonded to the system 0 V reference. The shield's ground terminal is not internally tied to the IOT2050's 0 V rail; it must be wired explicitly.1. Problem Overview
The typical failure pattern observed on production lines is:
- The IOT2050 boots the Example Image V1.2.1 (Basic) or V1.2.2 (Advanced) without errors.
-
mraa-gpio listenumerates 20+ GPIO lines includingIO0..IO13,A0..A5, andUSER. -
iot2050setupreports the GPIOs are configured as DI/DQ. - Toggling 24 V on the screw terminals of DI0 and DI1 has no effect on the corresponding
mraa-gpio getvalue. - The user LED and the USER button continue to respond, indicating the host CPU, libmraa, and Node-RED runtime are healthy.
Because the LED/USER button path is alive, the failure is isolated to the I/O shield's digital input front-end or the reference path shared by those inputs.
2. Root Cause Analysis
Three independent defects can produce the symptom set, and they must be ruled out in this order:
| # | Cause | Detection Method | Remedy |
|---|---|---|---|
| 1 |
M0 floating — the I/O shield's M terminal is not internally bonded to the IOT2050 0 V rail. A digital input without a return path cannot develop a logic level. |
Measure between shield M and shield DI0 with a DMM; if both read 0 V referenced to the IOT2050 chassis, the input is floating. |
Wire the shield M terminal to the IOT2050's chassis/protective earth or to the same 0 V used by the field 24 V supply. |
| 2 |
Pin number mismatch — the libmraa index for DI0 is 12, for DI1 is 11, for DI2 is 13, etc. The Arduino-shield D-labeling does not match the mraa index. |
Run mraa-gpio list and confirm the index associated with the SPI/UART bus that the shield's DI lines decode to. |
Use the corrected pin table in §4. |
| 3 |
Function-select set to SPI/UART/PWM — the on-board mux is configured via iot2050setup → Peripherals. If the SPI, UART, or PWM profile is selected, the DI lines are re-mapped to those peripherals and the GPIO read will always be 0. |
Open iot2050setup and inspect the Peripherals page; the relevant rows must read DI/DQ. |
Switch each affected row to DI/DQ (or HiZ if explicitly supported) and reboot. |
iot2050setup does apply.3. Affected Hardware and Software
| Component | Verified Value | Notes |
|---|---|---|
| SIMATIC IOT2050 Basic | PG2 (FS:01) / FS:02 | Reproduction in PG2 was negative; FS:02 originally reported as affected, then closed by R&D re-test. |
| SIMATIC IOT2050 Advanced | FS:05 | Reported with the Siemens Input/Output shield attached. |
| Example Image | V1.2.1 (Basic), V1.2.2 (Advanced) | Based on the meta-iot2050 Yocto layer. |
| libmraa | v2.2.0 | Confirmed via mraa-gpio version. |
| Siemens I/O Shield | 6ES7647-0KA01-0AA2 (Arduino Uno form-factor) | Provides 20× digital I/O, 6× analog I/O on the shield header. |
| Node-RED | Bundled with Example Image | Uses the IOT2050 GPIO palette (node-red-contrib-iot2050). |
4. IOT2050 Digital Input Pin Mapping
The shield's screw-terminal labels (DI0..DI19) are translated to libmraa GPIO indices by the meta-iot2050 board definition. The mapping is not one-to-one with the Arduino-shield header pins.
| Shield Terminal | libmraa Index | Arduino Header | Default Function |
|---|---|---|---|
| DI0 | 12 | D12 | SPI MOSI / DI |
| DI1 | 11 | D11 | SPI MOSI / DI |
| DI2 | 13 | D13 | SPI MISO / DI |
| DI3 | 10 | D10 | SPI CS / DI |
| DI4–DI7 | 4–7 | D4–D7 | PWM / DI |
| DI8–DI9 | 8–9 | D8–D9 | PWM / DI |
| DI10–DI13 | 0–3 | D0–D3 | UART / DI |
| DI14–DI17 | 4–7 (re-mirrored on Advanced shield variants) | — | Per shield BOM |
| DI18–DI19 | 12, 11 (mirror) | — | Per shield BOM |
| USER button | 20 | — | Fixed input |
Validate the live mapping on the target with:
root@IOT2050:~# mraa-gpio list
00 IO0: GPIO UART
01 IO1: GPIO UART
02 IO2: GPIO UART
03 IO3: GPIO UART
04 IO4: GPIO PWM
05 IO5: GPIO PWM
06 IO6: GPIO PWM
07 IO7: GPIO PWM
08 IO8: GPIO PWM
09 IO9: GPIO PWM
10 IO10: GPIO SPI
11 IO11: GPIO SPI
12 IO12: GPIO SPI
13 IO13: GPIO SPI
14 A0: GPIO AIO
15 A1: GPIO AIO
16 A2: GPIO AIO
17 A3: GPIO AIO
18 A4: GPIO I2C AIO
19 A5: GPIO I2C AIO
20 USER: GPIO
To read the IOT2050's software identity, run:
root@IOT2050:~# mraa-gpio version
Version v2.2.0 on SIMATIC IOT2050
5. Required Hardware Setup
Before any software investigation, verify the field wiring conforms to the IOT2050 manual:
- Connect the 24 V DC supply positive to the shield's
DI0(or DI1..DI19) screw terminal. - Connect the 24 V DC supply negative to the shield's
Mterminal. This is the step most often missed. - Bond the shield's
Mterminal to the IOT2050 chassis ground if the field 24 V supply is isolated from earth. - Confirm the shield is firmly seated on the Arduino Uno headers and that the retention screws are tightened to the specified 0.3 N·m torque.
M, the input optocoupler's LED has no current. The IOT2050 itself may be grounded through its DIN-rail clip or its functional-earth terminal, but the shield's M is not wired to either of these by default.6. Software Configuration with iot2050setup
Launch the configuration tool from the serial console or an SSH session:
root@IOT2050:~# iot2050setup
Navigate to Peripherals and inspect each GPIO group:
-
IO0–IO3 (UART/DI): must read
DI/DQfor the D0–D3 shield terminals to act as digital inputs. -
IO4–IO9 (PWM/DI): must read
DI/DQto expose D4–D9 as digital inputs. -
IO10–IO13 (SPI/DI): must read
DI/DQto expose D10–D13 as digital inputs.
For Advanced variants with a dedicated I/O shield, the same rule applies. The setting is persisted to /etc/iot2050-setup.conf and applied at the next boot. The change does not take effect without a reboot.
HiZ (high-impedance) option. Field testing on FS:05 / V1.2.2 shows the inputs still do not toggle while in HiZ; revert to DI/DQ and reboot before further investigation.7. Verifying Reads with mraa-gpio
Use the command-line tool to confirm the read path before bringing Node-RED into scope:
# Set pin 12 (DI0) as input
root@IOT2050:~# mraa-gpio set 12 in
# Read with 24 V applied to DI0, M0 bonded to 0 V
root@IOT2050:~# mraa-gpio get 12
1
# Remove 24 V, read again
root@IOT2050:~# mraa-gpio get 12
0
When the result is 0 in both states, repeat the hardware checklist in §5 before assuming a software fault.
8. Node-RED Integration Steps
Once mraa-gpio get toggles correctly, mirror the configuration in Node-RED:
- Open the Node-RED editor at
http://<iot2050-ip>:1880. - Drag an iot2050 in node onto the canvas.
- Set Pin to
12(DI0) or11(DI1) — do not use the Arduino header numberD12here; the IOT2050 GPIO node expects the libmraa index. - Set Mode to
Inputand leave the debounce at the default 10 ms unless bounce is observed. - Wire the node output to a
debugnode and deploy. - Toggle 24 V on DI0; the debug sidebar should show alternating
1/0payloads.
// Sample Node-RED flow (paste into a flow tab)
[
{
"id": "di0probe",
"type": "rpi-gpio in",
"z": "iot2050diag",
"name": "DI0 (pin 12)",
"pin": 12,
"intype": "tri",
"debounce": 10,
"read": false
},
{
"id": "debug1",
"type": "debug",
"z": "iot2050diag",
"name": "DI0 state",
"active": true
}
]
Note: the node-red-contrib-iot2050 palette wraps the same mraa indices used by mraa-gpio. If the palette is missing, install it with:
root@IOT2050:~# npm install -g node-red-contrib-iot2050
root@IOT2050:~# systemctl restart node-red
9. Step-by-Step Troubleshooting Procedure
Follow this sequence when a new shield is integrated or when a previously working station stops reading:
-
Confirm the host is healthy. Toggle the user LED via
mraa-gpio set 20 outandmraa-gpio set 20 1. If the LED responds, the CPU/libmraa path is intact. -
Inspect iot2050setup. Navigate to Peripherals and confirm
DI/DQfor IO0–IO13. Save and reboot if any row is mis-configured. - Power-cycle the shield. Remove shield 24 V, wait 5 s, re-apply. Some optocouplers latch in undefined states on brown-outs.
-
Verify M0 wiring. Place a DMM between the shield's
Mterminal and the field 24 V supply's0 V. Expect < 1 Ω. If open, install a jumper wire. - Drive a known input. Apply 24 V to DI0. Measure between DI0 and M with a DMM. Expect 24 V ±10 %.
-
Read with mraa-gpio.
mraa-gpio get 12should return1. If0, swap DI0 and DI1 (pin 11) to determine whether the fault is on a specific channel or all channels. - Cross-check on Node-RED. Wire the iot2050-in node as in §8. Confirm payload transitions.
-
Capture a syslog slice.
journalctl -u node-red -u iot2050-setup --since "-5 min"for any kernel/libmraa fault. - Escalate to R&D if all of the above pass and the read still fails on a known-good shield — this is the path that produced the original meta-iot2050 issue.
10. Verification and Field Validation
Once the input reads, perform a 24-hour soak test:
- Program a Node-RED flow that increments a counter on every DI0 rising edge and writes the value to a
filenode every minute. - Cross-check the counter against the upstream PLC's pulse count. Discrepancy > 0 indicates missed or extra edges.
- Inspect
journalctl -u node-redfor theEPIPEorENODEVerrors that occur when a GPIO handle is closed during a high-rate read.
For installations with electrical noise (variable-frequency drives, contactors), add:
- RC snubber (100 Ω + 100 nF) across the contactor coil feeding DI0..DI19.
- Shielded twisted pair from the field device to the IOT2050 shield with the shield bonded at the IOT2050 end only.
- Node-RED debounce raised to 25 ms for mechanical inputs.
11. Diagnostic Reference: Decision Matrix
| Symptom | First Check | Second Check | Most Likely Cause |
|---|---|---|---|
mraa-gpio get always 0
|
Bond M0 to 0 V |
iot2050setup Peripherals = DI/DQ | Floating reference |
Always 1
|
Wiring polarity | Shield seated correctly | Reversed 24 V / M |
Reads correctly, Node-RED payload always false
|
Node pin number set to header D12 not index 12
|
Palette version mismatch | Pin index vs header number |
Reads correctly, then drifts to 0
|
Field 24 V supply sagging | Shield thermal shutdown | Undersized PSU |
Reads 0 only on Advanced FS:05 |
Image version regression | Compare to FS:02 boot logs | FS-specific firmware bug |
12. Common Pitfalls and Field Tips
-
Don't trust the silkscreen. The screw terminal labeled
Mon the Siemens shield is not the same node as the IOT2050's chassis/protective-earth terminal. They must be wired. - Don't assume index = pin number. libmraa indices are remapped by the meta-iot2050 board file; the Arduino header numbering is cosmetic.
- Don't skip the reboot. iot2050setup Peripherals changes only take effect on the next boot. A common failure mode is changing the setting, deploying Node-RED, and concluding the tool is broken.
- Don't read at > 1 kHz without a queue. libmraa on the IOT2050 will drop edges on rapid GPIO reads because Node-RED's event loop yields. For high-speed counting, use the PRU-side counter on the IOT2050 Advanced or an external PLC.
- Don't mix 24 V and 5 V on the same shield. The IOT2050's shield header is 5 V tolerant; the I/O shield level-shifts to 24 V on the field side, but a 5 V signal injected on a 24 V-configured input will be read as a logic high only if the shield's resistor-divider is correct for the chosen mode.
FAQ
Why does my SIMATIC IOT2050 read 0 on all digital inputs even with 24 V applied?
The most common cause is a floating M0 (ground) terminal on the Siemens I/O shield. The shield's M terminal is not internally bonded to the IOT2050 chassis, so without a wire back to the field 24 V supply's 0 V, no current flows through the input optocoupler. Wire M0 to the supply's 0 V and re-test.
Which mraa-gpio pin number corresponds to DI0 and DI1?
DI0 maps to libmraa index 12 and DI1 maps to index 11 on the Siemens I/O shield. Do not use the Arduino header number (D12, D11) when configuring the IOT2050 GPIO Node-RED node or the mraa-gpio CLI; the palette expects the libmraa index.
Do I need a jumper on the I/O shield to read digital inputs?
No. The hardware jumper described in the IOT2050 manual is required only for analog inputs (A0–A5) to select voltage vs current mode. Digital inputs default to DI/DQ without a jumper, but they must be confirmed in iot2050setup → Peripherals.
How do I verify the iot2050setup configuration is DI/DQ?
Run iot2050setup from the shell, open the Peripherals page, and confirm each IO0–IO13 row reads DI/DQ. Save the change, reboot, then re-test with mraa-gpio get 12. The USER button (index 20) is not affected by this setting.
Which IOT2050 image versions are known to work for digital input reading?
Example Image V1.2.1 on IOT2050 Basic and V1.2.2 on IOT2050 Advanced, both with libmraa v2.2.0, have been validated in the field after the M0 grounding fix. If a regression appears, capture mraa-gpio version and journalctl -u node-red before escalating to Siemens support.