Project PMDG-NGX-MCP for Arduino

Full functioning MCP for PMDG NGX


  • Arduino Uno (but I’m sure other platforms will do also)
  • FSIO MCP hardware (unchanged)

As all of my software, the arduino sketch is available through my forum for registered members (free).


My FSIO architecture is bases on SIOC as a central scripting and configuration engine. See FSIO overview. This is clearly the way to go if you want to construct a full functioning cockpit.

Based in the information about the PMDGDataEventServer that I made to integrate within FSIO I got request through this site if I could make the PMDGDataEventServer available for Arduino build panels. The base structure of the PMDGDataEventServer did not need to change for that. I just had to make serial interfaces and strip away al; SIOC related code. (you can find it here)

From comments that I receive I think this program is a breakthrough for Arduine based panel builders that want to build panels for their PMDG NGX.

The next challenge I put myself is to investigate if FSIO based panel units could be connected to Arduino. (General information about FSIO panel hardware can be found here).

Sure they can without modification.

I assume that you have read and studied the PMDGDataEventServer for Arduino (serial interface). If you understand the workings of the example Arduino program, you should not have any problem making your own MCP.

Some background

The basic difference between FSIO CPU micro code is that the FSIO micro code is general and not aware if the specific  functions or panels. The complexity and specifics of the various panels are solved within the SIOC script. Arduino bases panel software contains all panel specific code.

I ported lots of the code that I wrote for the FSIO CPU to an Arduino ino. This code deals with switches, buttons, rotary encoders, displays and LED indicators. This is general code and not panel function aware. If you use this code as a base you sould not have to modify these parts.

I took my already existing MCP (see Most Complex Panel Unit MCP) and connected it to the Arduino SPI port.

So the Arduino code consist of 2 parts:

  1. General code to scan switches and rotary encoders.
    General code to allow setting displays and indicators
    General code to communicate with the PMDG Data Event Server
  2. Panel specific code.

Panel Specific Code

This is the only part that the user/builder needs to deal with. The uses that wants to write his own panel specific code will have to program 4 functions:

void RegisterVariables()
This function will be called when the Arduino is connected to the PMDGDataEventServer. The PMDGDataEventServer sends a ‘Ready’ message. Now this function will send a registration request to PMDGDataEventServer for all PMDG Data variables it requires.

void ButtonPressed(byte Button, byte ONOF)
This function will be called when the general code detects a button, switch or rotary encode detects a push, release or rotate.
The function in fact is a large switch-case tree to handle the specifics of the button etc. Mostly sending an event to the PMDGDataEvent server.

void HandleVariableReceived()
This function will be called when data is received from the PMDGDataEventServer.  As the code is not multy thread, the data is in global variables (ivar,ivalue,cvalue).

Also this function is one large switch-case: tree. To handle the specifics of the data received.

void DoBlinks()
This function is periodically called and facilitates blinking of LED’s of Displays like Overspeed and Underspeed.

This is it!!! All other code is common and not panel specific. The user does not have to touch this code.

Functions available for user code

The user/writer of the above function will need:

SendEvent(Event Number, Event Data)

Read about PMDG NGX events here.

ToDisplay(start digit, number of characters)
As the code is single thread I rely on the data received to be in global variables. So I could keep the function call simple.

Start digit number is the rightmost digit. 7-Segment display digits are placed and numbered form right to left.

SetLed(Number, value)
In FSIO panel hardware all segments of a maxim 7219 can be wired as LED. I do not use the Max7219 bcd to 7-segment decoder. 7-segments characters are bdc-7-segment translated in software.

Picture of the Arduino Uno (other Arduino’s will do too) connected to the SPI interface of the MCP Panel PCB.

On screen at the right you see the PMDG DataEvenServer.

I will make the code available through my forum


The code


Find here the pin selections for the SPI interface and the CS for input and output chains.

NUMBER OF MAXIMS 3 (the total number of MAXIM 7219 chips in the chain. This can be easely set to at least 8, allowing 64 7 segment digits or 265 LED’s. I did not test this, but from calculations I made this can easily be set to 16.

BUTTON_GROUP_SIZE 5 (the total number of 74LS165 input chips in the chain.) You could set this up to 32. In fact if you do, non connected chips are ignored.

DEBOUNCE_BUFFER_DEPTH 4. Leave this set to 4.

segments[20] . The MAXIM chips are set to non decode. Meaning we have to set individual segements by software. This is the lookup table for the segments of 0-9 and allow additional characters.


If you have read my page about FSIO panel hardware you know that buttons, switches and rotary encoders are connected to a chain of 74..165 chips. Rotaty encoders need 2 consequetive inputs. It is important that the microcode knows where rotary encoders are connected and what type they are. Read about rotary encoder types here.

In the source you find 2 arays:

byte EncoderConfig[BUTTON_GROUP_SIZE] = {0XF0, 0X18, 0XC6, 0x0C};
byte EncoderType[BUTTON_GROUP_SIZE] =   {0XF0, 0X18, 0XC6, 0x0C};

Each byte in the aray represents one 74..165 input chip. If a rorary encoder is connected the 2 bit representing the rotatary encoder need to be set to 1.

In the above chip 0 (the chip closest to the input of the arduino) has a roraty encoder connected to bits 6 and 7. This rorary encode when turned wil send +1 of -1 from button 6.

The parallel bits in the EncoderType indicate the type of encoder. In the above these bits are 11=3. So the type is 3, full cycle.

The next rotary encoder is on inputs 3 and 4 of the second chip. 0X18. This ‘button’ will represent itself as number  11 ( 8 + 3) etc.

Sending Events

Switches, like FD. AT-ARM can be toggled using mouse click events and directly set the value. The up position in PMDG is always 0. Depending on how you mounted the switch you might need to invert the value the switch sends to set the panel switch direct.


If you understand Panel Hardware you understand that panels can be chained. So this means that you could build an EFIS anel unit Panel Unit and chain in to the MCP. You will need to expand the INO to facilitate that, but if you also understand Arduino and network interface to PMDG Data and Events that should be an easy task.