A scalable IR transmission platform with dual implementations: 24-channel parallel FPGA-based transmitter (PYNQ-Z2) and Arduino-only alternative. Decode and test IR signals using dual Arduino Uno receivers with NEC-inspired protocol support.
- Project Overview
- System Architecture
- Project Structure
- Hardware Setup
- Software Setup & Installation
- Usage Guide
- IR Protocol Specification
- Customization & Development
- Troubleshooting
- Appendix
This project implements a high-capacity parallel IR transmission system designed for:
- Research & Testing: Transmit multiple IR signals simultaneously to evaluate receiver performance
- Device Control: Send NEC-compatible IR commands to multiple devices in parallel
- System Integration: Flexible architecture supporting both FPGA and Arduino implementations
Key Features:
- ✅ 24 parallel IR transmitter channels (FPGA version) — TESTED & WORKING
- ✅ Simultaneous multi-channel transmission with independent control
- ✅ Dual Arduino receiver validation setup
- ✅ NEC IR protocol support with custom extensions
- ✅ Low-cost Arduino-only fallback implementation
- ✅ Real-time signal monitoring and debugging
⚠️ Status: FPGA IR receiver (PL design) is NOT YET TESTED. Transmitter functionality is stable. Use external Arduino receivers for validation.
| Aspect | FPGA Version | Arduino Version |
|---|---|---|
| Transmitter | PYNQ-Z2 FPGA (24 channels) | Arduino Uno (1 channel) |
| Receivers | 2× Arduino Uno or external receiver | 1× Arduino + external receiver |
| Complexity | Advanced (Vivado design) | Simple (single sketch) |
| Cost | Higher | Lower |
| Scalability | 24 parallel channels | Single sequential channel |
| Use Case | Bulk testing, research | Hobbyist, simple control |
PYNQ-Z2 Board
├─ Processing System (PS) — ✅ TESTED
│ └─ Python/Jupyter Controller (nec_onlyFPGA.ipynb)
├─ Programmable Logic (PL)
│ ├─ NEC_IR_Receiver IP cores (×2) — ⚠️ NOT YET TESTED
│ ├─ IR_Transmission IP cores (×24) — ✅ TESTED
│ └─ AXI GPIO interfaces
└─ Physical I/O
├─ 24× IR LED outputs (AR0-AR13, A0-A5, PMODA) — ✅ TESTED
└─ 2× status/control pins
Receiver Setup (External - Recommended)
├─ Arduino Uno (Blue) → Pin 11 (Receiver 1) — ✅ TESTED
└─ Arduino Uno (Green) → Pin 10 (Receiver 2) — ✅ TESTED
Parallel_IR_Transmitters/
│
├── 📄 README.md # This file
├── 📄 IR_research.pdf #
research that I conduct now
│
├── 📂 PS\ part/ # FPGA Processing System (PS) - Python Side
│ ├── 📓 nec_onlyFPGA.ipynb # Jupyter notebook for PYNQ-Z2
│ │ # - NEC_IR_Controller_24ch class
│ │ # - Command transmission logic
│ │ # - Real-time control interface
│ │
│ ├── 📂 xilinx/overlays/own/
│ │ ├── design_1_wrapper.bit # FPGA bitstream file
│ │ └── design_1_wrapper.hwh # Hardware handoff file
│ │
│ └── 📂 arduino\ part/
│ ├── 📂 IR_TransmitterReceiver/ # Receiver sketch (standard)
│ │ └── IR_TransmitterReceiver.ino
│ └── 📂 IR_Receiver2/ # Receiver sketch (variant)
│ └── IR_Receiver2.ino
│
├── 📂 FPGA_Part/ # FPGA Programmable Logic (PL) - Vivado Design
│ ├── 📂 Own_IR_receiver/ # Vivado project (receiver reference) ⚠️ NOT TESTED
│ │ ├── Own_IR_Receiver.xpr
│ │ ├── design_1_wrapper.bit
│ │ └── [Vivado build artifacts]
│ │
│ └── 📂 Own_IR_transmitter/ # Vivado project (24-channel transmitter) ✅ TESTED
│ ├── Own_IR_transmitter.xpr
│ ├── design_1_wrapper.xsa
│ └── [Vivado build artifacts]
│
├── 📂 external_design/ # Circuit Design Files
│ ├── External_circuit.asc # 24 VCC GND port (SPICE)
│ ├── Safe_Driving_Circuit.asc # Protected driver circuit (SPICE)
│ ├── Driving_Ciruit.asc # Alternative driver (SPICE)
│ └── 📂 Altium/ # PCB Design (Altium Designer)
│ ├── 📂 24_external/ # 24-channel external driver PCB
│ │ ├── PcbLib1.PcbLib
│ │ ├── PCB_Project/
│ │ └── __Previews/
│ └── 📂 Driving_Circuit/ # Driving circuit PCB
│ └── Control_Circuit_safe/
│
├── 📂 No_FPGA_approach/ # Arduino-Only Alternative
│ └── 📂 IR_transmitter/
│ └── IR_transmitter.ino # Standalone Arduino TX sketch
│
├── 📂 Metasurface\ research_papers/ # Research Reading Materials
│ ├── My\ list.txt # Curated reading list
│ └── 📂 Step0/ # Research progress notes
│ └── Step\ to\ take\ here.txt
│
└── 📂 img/ # Hardware photos & diagrams
├── WhatsApp\ Image\ 2026-03-09\ at\ 17.52.39.jpeg
├── image-1.png
├── image-2.png
├── image-3.png
└── Image_for_more.png
The external_design/Altium/ folder contains complete PCB designs created with Altium Designer:
- Directory:
external_design/Altium/24_external/ - Purpose: Dedicated driver PCB for all 24 parallel IR LED transmitters
- Features:
- 24 independent driver channels with current limiting
- Thermal management and RF shielding considerations
- Integration connectors for FPGA board
- PCB Library files and design projects included
- Directory:
external_design/Altium/Driving_Circuit/ - Purpose: Individual IR LED driver circuit design
- Features:
- Optimized for single or multi-channel configurations
- Safe switching circuitry with transient suppression
- References corresponding SPICE simulations in
external_design/
Complementary SPICE circuit files for simulation and verification:
External_circuit.asc— 24-port external interface with VCC/GND distributionSafe_Driving_Circuit.asc— Protected driver with feedback and current monitoring
Recommendation: Review SPICE simulations before PCB manufacturing to validate signal integrity and power delivery.
Located in Metasurface\ research_papers/ folder:
- My list.txt — Curated list of important research papers and technical references related to the project
- Step0/ — Research progress notes and next steps for metasurface and IR transmission investigations
- IR transmission physics and optimization
- Metasurface applications for RF/IR engineering
- Signal processing and modulation techniques
- High-speed parallel data transmission
📖 Note: These materials provide theoretical background and advanced optimization strategies for future enhancements.
| Component | Quantity | Purpose |
|---|---|---|
| PYNQ-Z2 FPGA Board | 1 | Main controller (24-channel TX) |
| Arduino Uno | 2 | IR signal receivers + validation |
| IR LED Emitter | 24 | Transmitter elements (FPGA outputs) |
| IR Receiver Module | 2 | Signal decoders (1 per Arduino) |
| Driver Circuit | 24 | LED current limiting & switching |
| Copper sheet / barrier | 1 | RF isolation between TX channels |
| Jumper wires | ~100 | Interconnections |
| USB cables | 3 | PYNQ power, Arduino programming |
| Ethernet cable | 1 | PYNQ network (optional but recommended) |
| Component | Quantity | Purpose |
|---|---|---|
| Arduino Uno | 1 | IR transmitter controller |
| IR LED Emitter | 1 | Transmitter element |
| Driver Circuit | 1 | LED current limiting |
| Jumper wires | ~60 | Interconnections |
| USB cable | 1 | Power & programming |
| Channel | PYNQ-Z2 Pin | Driver Output |
|---|---|---|
| 1-8 | AR0-AR7 | IR LED Array 1 |
| 9-13 | AR8-AR12 | IR LED Array 2 |
| 14-19 | A0-A5 | IR LED Array 3 |
| 20-24 | PMODA0-PMODA4 | IR LED Array 4 |
Each pin: 3.3V logic → Buffer/Driver → IR LED anode (cathode to GND through 100Ω resistor)
- ⚡ Micro-USB cable to computer or dedicated 5V supply
- 🌐 Gigabit Ethernet cable for robust network connection to Jupyter server
| Component | Pin |
|---|---|
| IR Receiver Data | GPIO 11 |
| IR Receiver VCC | 5V |
| IR Receiver GND | GND |
| Component | Pin |
|---|---|
| IR Receiver Data | GPIO 10 |
| IR Receiver VCC | 5V |
| IR Receiver GND | GND |
- USB cables to different COM ports
Click to expand hardware documentation
FPGA Board + 24 IR Transmitter Array:

Arduino 1 (Blue) with IR Receiver Module:

Arduino 2 (Green) with IR Receiver Module:

- PYNQ-Z2 board with latest firmware
- 2× Arduino Uno boards
- Computer with USB ports
- Python 3.6+ (for local scripts)
- Arduino IDE 1.8+ (for sketches)
- Connect PYNQ-Z2 via Micro-USB and Ethernet to your network
- Power on and wait 2-3 minutes for boot
- Find the board's IP address (default:
192.168.2.99) - Reference: PYNQ Setup Guide
- Open browser:
http://192.168.2.99:9090/ - Password:
xilinx - Create a working folder (e.g.,
IR_Project)
Upload to PYNQ Jupyter server:
| Local File | Server Destination |
|---|---|
PS\ part/nec_onlyFPGA.ipynb |
~/IR_Project/ |
PS\ part/xilinx/overlays/own/design_1_wrapper.bit |
~/IR_Project/xilinx/overlays/own/ |
PS\ part/xilinx/overlays/own/design_1_wrapper.hwh |
~/IR_Project/xilinx/overlays/own/ |
- Open Arduino IDE
- Install library: Arduino-IRremote (Sketch → Include Library → Manage Libraries)
- Load:
PS\ part/arduino\ part/IR_TransmitterReceiver/IR_TransmitterReceiver.ino - Select Tools → Board → Arduino Uno
- Connect Arduino 1, select its COM port, upload
- Repeat with Arduino 2 on a different COM port
- Open both Arduino Serial Monitors (9600 baud)
- Run Jupyter notebook test cell
- Should see "Overlay loaded" message
- Open Arduino IDE
- Install Arduino-IRremote library
- Load:
No_FPGA_approach/IR_transmitter/IR_transmitter.ino - Modify pin assignments if needed (currently D2)
- Upload to single Arduino Uno
- Connect IR LED via driver circuit to D2 pin
- Open Serial Monitor (9600 baud) to send commands
- On PYNQ server: Open
nec_onlyFPGA.ipynb - Run cell 1: Loads
NEC_IR_Controller_24chclass and initializes FPGA
Example 1: Send commands
# In notebook cell:
controller = NEC_IR_Controller_24ch(
ir = NEC_IR_Controller_24ch(
"/home/xilinx/jupyter_notebooks/xilinx/overlays/own/design_1_wrapper.bit",
tx_bases=tx_bases,
btn_base=btn_base
)
try:
start = datetime.now()
# Each tx needs address and a command string of equal length
tx_addresses = [0x00]*24
# Example addresses
cmd_strs = [
"-0001+", # Channel 0: 5
"-0013+", # Channel 1: 6
"-0106+", # Channel 2: 7
"-0008+", # Channel 3: 8
"-0009+", # Channel 4: 9
"-0010+", # Channel 5: 10
"-0011+", # Channel 6: 11
"-0012+", # Channel 7: 12
"-0013+", # Channel 8: 13
"-0014+", # Channel 9: 14
"-0015+", # Channel 10: 15
"-0016+", # Channel 11: 16
"-0017+", # Channel 12: 17
"-0018+", # Channel 13: 18
"-0019+", # Channel 14: 19
"-0020+", # Channel 15: 20
"-0021+", # Channel 16: 21
"-0022+", # Channel 17: 22
"-0023+", # Channel 18: 23
"-0024+", # Channel 19: 24
"-0025+", # Channel 20: 25
"-0026+", # Channel 21: 26
"-0027+", # Channel 22: 27
"-0028+", # Channel 23: 28
]
)
# Transmit on channels 1 and 2 simultaneously
controller.send_cmd(0, '1') # Transmitter 0, command '1'
controller.send_cmd(1, 'B') # Transmitter 1, command 'B'- Check Serial Monitor on each Arduino
- Output format:
Address: 0xXX, Command: 0xXX - Timing: Signals should arrive within 100ms
- Open Arduino Serial Monitor at 9600 baud
- Type a character and press Enter
- Predefined mappings (0-9, A-F) send NEC codes
- Received signals can be monitored with external receiver
Edit the Send_Code() function:
case 'X':
IrSender.sendNEC(0x12345678, 32);
break;| Parameter | Value | Notes |
|---|---|---|
| Standard | NEC-compatible | Simplified NEC implementation |
| Total Frame Bits | 32 bits | Address + Command + Parity |
| Address Bits | 8 bits | Device identifier |
| Command Bits | 8 bits | Action/button code |
| Carrier Frequency | ~38 kHz | Standard IR frequency |
| Modulation | PWM (50% duty) | On-off keying |
| Protocol Channels | 24 (parallel FPGA) | Independent TX channels |
┌─ 32 bits total ─┐
│ Address (8b) │ Command (8b) │ ~Address (8b) │ ~Command (8b) │
└────────────────┘
- Address Field: Device identifier (0x00-0xFF)
- Command Field: Action code (0x00-0xFF)
- Inverse Fields: Checksum/error detection
| Key | Code | Key | Code |
|---|---|---|---|
| 0 | 0x16 | 8 | 0x52 |
| 1 | 0x0C | 9 | 0x4A |
| 2 | 0x18 | A | 0xAA |
| 3 | 0x5E | B | 0xBB |
| 4 | 0x08 | C | 0xCC |
| 5 | 0x1C | D | 0xDD |
| 6 | 0x5A | E | 0xEE |
| 7 | 0x42 | F | 0xF1 |
- FPGA Transmitter (24 channels): All transmitter channels working as designed
- Arduino Receivers: Both receiver boards successfully decode NEC signals
- Python/Jupyter Interface: Notebook controller and MMIO communication verified
- Protocol Implementation: Standard NEC encoding/decoding functional
- FPGA Receiver (PL design): NEC_IR_Receiver IP cores in the FPGA bitstream have not been validated
- Reason: Focus was on transmission performance; receiver testing deferred
- Recommendation: Use external Arduino receivers for current applications
- Future: Will integrate FPGA receiver testing in next release
- FPGA receiver functionality cannot be guaranteed in production
- No loopback testing between FPGA TX and FPGA RX
- All receiver-side validation currently relies on Arduino Uno boards and external circuits
| Symptom | Cause | Solution |
|---|---|---|
| No Jupyter server response | Board not powered | Check USB power indicator LED |
| Connection timeout | Network misconfiguration | Ping board IP: ping 192.168.2.99 |
| Overlay failed to load | Bitstream path incorrect | Verify .bit and .hwh files exist in correct directory |
| MMIO initialization error | Wrong base address | Verify address map in Vivado design |
| Symptom | Cause | Solution |
|---|---|---|
| No IR signal | LED not powered | Check driver circuit continuity (multimeter) |
| Weak/short-range signal | Insufficient LED current | Reduce resistor value (100Ω → 50Ω) |
| No receiver output | Receiver placement | Point LED directly at receiver (within 1 meter) |
| Garbled data | Baud rate mismatch | Set both Arduino + Serial Monitor to 9600 baud |
| Channel interference | No RF isolation | Place copper barrier between TX LED arrays |
| Symptom | Cause | Solution |
|---|---|---|
| Sketch upload fails | Wrong COM port | Tools → Port → Select correct COM port |
| Serial Monitor shows garbage | Baud mismatch | Set Serial Monitor to 9600 baud |
| Library not found | IRremote not installed | Sketch → Include Library → Manage Libraries → Search "IRremote" → Install |
| Symptom | Cause | Solution |
|---|---|---|
| Slow transmission | Jupyter kernel lag | Restart kernel: Kernel → Restart |
| Dropped frames | High FPGA load | Increase delay between transmissions (NEC_HOLD_TIME) |
| Inconsistent reception | Weak carrier frequency | Verify crystal oscillator on FPGA board |
- PYNQ Official Documentation: https://pynq.readthedocs.io/
- Vivado Design Suite: https://www.xilinx.com/products/design-tools/vivado.html
- NEC IR Protocol: https://www.sbprojects.net/knowledge/ir/nec.php
- Arduino-IRremote Library: https://github.com/Arduino-IRremote/Arduino-IRremote
PCB Design Files:
external_design/Altium/24_external/— Complete 24-channel driver PCB (Altium Designer)external_design/Altium/Driving_Circuit/— Individual LED driver PCB design
SPICE Circuit Simulations:
external_design/External_circuit.asc— VCC GND distribution circuitexternal_design/Safe_Driving_Circuit.asc— Protected version with feedbackexternal_design/Driving_Ciruit.asc— Standard IR LED driver
Metasurface\ research_papers/My\ list.txt— Curated reading list for IR transmission and metasurface topicsMetasurface\ research_papers/Step0/— Research progress notes and investigation roadmap
- nec_onlyFPGA.ipynb: Main control interface for 24-channel transmission
- IR_research.pdf: Research in a topic
- Own_IR_transmitter.xpr: Vivado project (24-channel implementation)
- Own_IR_receiver.xpr: Vivado project (receiver reference design)
This project builds upon:
- PYNQ framework (Xilinx/University of Sydney)
- Arduino IDE & libraries (Arduino LLC)
- NEC IR protocol (reverse-engineered standard)
Last Updated: June 2026
Status: Transmitter Stable | Receiver Under Development | PCB Design Complete


