The Arduino MKR Vidor 4000 is a powerful but also mysterious board. The FPGA gives it a performance boost over other Arduinos but its functions are very badly documented. There are also very few code examples available on the internet.

 

Mini PCIe connector of the Vidor

 

I took a closer look at the Mini PCIe connector and wanted to see which functions are available at these pins.

 

This connector has 52 positions and the pinout can be grabbed from the official schematics of the board:

 

Pin
Usage on Vidor
Usage on Mini PCIe cardUsage on Mini PCIe cardUsage on VidorPin
1WM_PIO2/PEX_PIN1WAKE#+3V3AUX+3V32
3WM_PIO3/PEX_PIN3COEX1GNDGND4
5WM_PIO4/PEX_PIN5COEX2+1.5VPEX_PIN66
7WM_PIO34/PEX_PIN7CLKREQ#UIM_PWRPEX_PIN88
9GNDGNDUIM_DATAPEX_PIN1010
11PEX_PIN11REFCLK-UIM_CLKPEX_PIN1212
13PEX_PIN13REFCLK+UIM_RESETPEX_PIN1414
15GNDGNDUIM_VPPPEX_PIN1616
17WM_PIO24RESERVEDGNDGND18
19WM_PIO25RESERVEDW_DISABLE#PEX_PIN2020
21GNDGNDPERST#PEX_RST22
23PEX_PIN23PERn0+3.3VAUX+3V324
25PEX_PIN25PERp0GNDGND26
27GNDGND+1.5VPEX_PIN2828
29GNDGNDSMB_CLKPEX_PIN3030
31PEX_PIN31PETn0SMB_DATAPEX_PIN3232
33PEX_PIN33PETp0GNDGND34
35GNDGNDUSB_D-USB_DM36
37GNDGNDUSB_D+USB_DP38
39+3V3+3.3VAUXGNDGND40
41+3V3+3.3VAUXLED_WWAN#PEX_PIN4242
43GNDGNDLED_WLAN#PEX_PIN4444
45PEX_PIN45RESERVEDLED_WPAN#PEX_PIN4646
47PEX_PIN47RESERVED+1.5VPEX_PIN4848
49PEX_PIN49RESERVEDGNDGND50
51PEX_PIN51RESERVED+3.3VAUX+3V352

 

So the Vidor is somehow compatible to any standard Mini PCIe header used in computers. At least the GND and 3.3V pins are at the same location as well as the USB pins. On the Vidor the USB pins on the Mini PCIe connector are directly connected to the Micro USB connector on the other end of the board. So when plugged into a  Mini PCIe socket on a computer it might be possible to programm the Vidor without using an additional USB cable.

 

After reset and when nothing is programmed all these pins are inputs. So nothing bad should happen if you plug it into your computer. But care must be taken when you programm the pins. Putting a high level (3.3V) on some of the 1.5V pins might carry some risk of damage.

 

Using the pins as GPIOs is quite simple. Actually it is already shown in the VidorTestSketch ( https://github.com/vidor-libraries/VidorPeripherals/blob/master/examples/VidorTestSketch/VidorTestSketch.ino  ):

  // Ok, so we know now that the FPGA contains the extended GPIO IP
  // Please refer to the online documentation for the actual pin assignment
  // Let's configure pin A0 to be an output, controlled by the FPGA
  FPGA.pinMode(33, OUTPUT);
  FPGA.digitalWrite(33, HIGH);

 

The difficult part is to figure out why they use 33 as pin number. It is somehow common knowledge that MKR pins (AREF,A0..A6, D0..D14) have the numbers 32 to 54 assigned. So A0 is 33, A1 is 34 and so on. D14 is 54.

 

But what about the pins on the Mini PCIe connector? When you dig deep into the Arduino Vidor Forum you find a spreadsheet with the mapping:

https://docs.google.com/spreadsheets/d/1oAL1Iz39eCHi0IVyMiTRyekmzJg5TgeyO5t0fN6Vl4U/edit#gid=0

 

The tab "miniPCIe pinout" shows the mapping.

 

Mini PCIe connector pin

NameNumber in FPGA (software)
Comment
22PEX_RST0
6PEX_PIN61
8PEX_PIN82
10PEX_PIN103
12PEX_PIN124
14PEX_PIN145
16PEX_PIN166
20PEX_PIN207
28PEX_PIN288
30PEX_PIN309
32PEX_PIN3210
42PEX_PIN4211
44PEX_PIN4412
45PEX_PIN4513
46PEX_PIN4614
47PEX_PIN4715
48PEX_PIN4816
49PEX_PIN4917
51PEX_PIN5118
11PEX_PIN1119this pin is only an input
13PEX_PIN1320this pin is only an input
23PEX_PIN2321this pin is only an input
25PEX_PIN2522this pin is only an input
31PEX_PIN3123this pin is only an input
33PEX_PIN3324this pin is only an input

 

And for my test this proved to be right.

 

VidorBreakout board

 

To access the pins one could directly solder cables to the pads which is a bit tricky or use an adapter. I couldn't find a good adapter so I made my own. You can find the data here:

https://github.com/generationmake/VidorBreakout

 

Rendering of VidorBreakout

 

The breakoutboard connects all GND and 3.3V pins and brings only the GPIOs seperately to the pinheader. Additionally the Vidor can be directly srewed onto the adapter with a M2.5 screw and both form a solid unit.

 

The design was made using 3D models and FreeCAD so that there is no collision.

 

Rendering of VidorBreakout with Arduino MKR Vidor 4000 on base board

 

The adapte follows the 2.54 mm grid of the Vidor. So both could plugged into a breadboard. Althought you would need a special breadboard because the adapter is wider that a regular breadboard.

Arduino MKR Vidor 4000 with VidorBreakout on breadboard

To demonstrate the function of the GPIOs and the adapter I made a LED sequence using 17 green 3mm LEDs with a 3.3 kOhm resistor connected to ground.

LED sequencer with Arduino MKR Vidor 4000 and VidorBreakout

 

Unfortunately I couldn't find any more functions which are supported on the Mini PCIe connector pins. Hopefully this changes in the future.

 

Boards and parts are available at Aisler: https://aisler.net/p/VKRNBJOG

 

Software

 

This is the source code of my LED sequence:

 

#include "VidorPeripherals.h"
#define STARTDELAY 500

void setup() {
  Serial.begin(115200);
//  while (!Serial) {}
  // Let's start by initializing the FPGA
  if (!FPGA.begin()) {
    Serial.println("Initialization failed!");
    while (1) {}
  }

  // Let's discover which version we are running
  int version = FPGA.version();
  Serial.print("Vidor bitstream version: ");
  Serial.println(version, HEX);
  pinMode(LED_BUILTIN, OUTPUT);

  // Let's also ask which IPs are included in this bitstream
  FPGA.printConfig();

  // Ok, so we know now that the FPGA contains the extended GPIO IP
  // Please refer to the online documentation for the actual pin assignment
  // Let's configure pin A0 to be an output, controlled by the FPGA
  FPGA.pinMode(0, OUTPUT);
  FPGA.pinMode(1, OUTPUT);
  FPGA.pinMode(2, OUTPUT);
  FPGA.pinMode(3, OUTPUT);
  FPGA.pinMode(4, OUTPUT);
  FPGA.pinMode(5, OUTPUT);
  FPGA.pinMode(6, OUTPUT);
  FPGA.pinMode(7, OUTPUT);
  FPGA.pinMode(8, OUTPUT);
  FPGA.pinMode(9, OUTPUT);
  FPGA.pinMode(10, OUTPUT);
  FPGA.pinMode(11, OUTPUT);
  FPGA.pinMode(12, OUTPUT);
  FPGA.pinMode(13, OUTPUT);
  FPGA.pinMode(14, OUTPUT);
  FPGA.pinMode(15, OUTPUT);
  FPGA.pinMode(16, OUTPUT);
  FPGA.pinMode(17, OUTPUT);
  FPGA.pinMode(18, OUTPUT);
  FPGA.pinMode(33, OUTPUT);
  FPGA.digitalWrite(33, HIGH);

  // The same pin can be read by the SAMD processor 
  pinMode(A0, INPUT);
  Serial.print("Pin A0 is ");
  Serial.println(digitalRead(A0) == LOW ? "LOW" : "HIGH");

  FPGA.digitalWrite(33, LOW);
  Serial.print("Pin A0 is ");
  Serial.println(digitalRead(A0) == LOW ? "LOW" : "HIGH");
}

void loop() {
  // put your main code here, to run repeatedly:
  int delaytime=STARTDELAY;

  FPGA.digitalWrite(1, HIGH);
  FPGA.digitalWrite(2, HIGH);
  FPGA.digitalWrite(3, HIGH);
  FPGA.digitalWrite(4, HIGH);
  FPGA.digitalWrite(5, HIGH);
  FPGA.digitalWrite(6, HIGH);
  FPGA.digitalWrite(7, HIGH);
  FPGA.digitalWrite(0, HIGH);
  FPGA.digitalWrite(8, HIGH);
  FPGA.digitalWrite(9, HIGH);
  FPGA.digitalWrite(10, HIGH);
  FPGA.digitalWrite(11, HIGH);
  FPGA.digitalWrite(12, HIGH);
  FPGA.digitalWrite(13, HIGH);
  FPGA.digitalWrite(14, HIGH);
  FPGA.digitalWrite(15, HIGH);
  FPGA.digitalWrite(16, HIGH);
  delay(delaytime);
  FPGA.digitalWrite(1, LOW);
  FPGA.digitalWrite(2, LOW);
  FPGA.digitalWrite(3, LOW);
  FPGA.digitalWrite(4, LOW);
  FPGA.digitalWrite(5, LOW);
  FPGA.digitalWrite(6, LOW);
  FPGA.digitalWrite(7, LOW);
  FPGA.digitalWrite(0, LOW);
  FPGA.digitalWrite(8, LOW);
  FPGA.digitalWrite(9, LOW);
  FPGA.digitalWrite(10, LOW);
  FPGA.digitalWrite(11, LOW);
  FPGA.digitalWrite(12, LOW);
  FPGA.digitalWrite(13, LOW);
  FPGA.digitalWrite(14, LOW);
  FPGA.digitalWrite(15, LOW);
  FPGA.digitalWrite(16, LOW);
  delay(delaytime);

  for(delaytime=STARTDELAY;delaytime-=100;delaytime>0)
  {
    digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
    delay(delaytime);
    digitalWrite(LED_BUILTIN, HIGH);    // turn the LED off by making the voltage LOW
    FPGA.digitalWrite(1, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(1, LOW);
    FPGA.digitalWrite(2, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(2, LOW);
    FPGA.digitalWrite(3, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(3, LOW);
    FPGA.digitalWrite(4, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(4, LOW);
    FPGA.digitalWrite(5, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(5, LOW);
    FPGA.digitalWrite(6, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(6, LOW);
    FPGA.digitalWrite(7, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(7, LOW);
    FPGA.digitalWrite(0, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(0, LOW);
    FPGA.digitalWrite(8, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(8, LOW);
    FPGA.digitalWrite(9, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(9, LOW);
    FPGA.digitalWrite(10, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(10, LOW);
    FPGA.digitalWrite(11, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(11, LOW);
    FPGA.digitalWrite(12, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(12, LOW);
    FPGA.digitalWrite(13, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(13, LOW);
    FPGA.digitalWrite(14, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(14, LOW);
    FPGA.digitalWrite(15, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(15, LOW);
    FPGA.digitalWrite(16, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(16, LOW);
  }
  for(delaytime=STARTDELAY;delaytime-=100;delaytime>0)
  {
    FPGA.digitalWrite(1, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(2, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(3, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(4, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(5, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(6, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(7, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(0, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(8, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(9, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(10, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(11, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(12, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(13, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(14, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(15, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(16, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(1, LOW);
    delay(delaytime);
    FPGA.digitalWrite(2, LOW);
    delay(delaytime);
    FPGA.digitalWrite(3, LOW);
    delay(delaytime);
    FPGA.digitalWrite(4, LOW);
    delay(delaytime);
    FPGA.digitalWrite(5, LOW);
    delay(delaytime);
    FPGA.digitalWrite(6, LOW);
    delay(delaytime);
    FPGA.digitalWrite(7, LOW);
    delay(delaytime);
    FPGA.digitalWrite(0, LOW);
    delay(delaytime);
    FPGA.digitalWrite(8, LOW);
    delay(delaytime);
    FPGA.digitalWrite(9, LOW);
    delay(delaytime);
    FPGA.digitalWrite(10, LOW);
    delay(delaytime);
    FPGA.digitalWrite(11, LOW);
    delay(delaytime);
    FPGA.digitalWrite(12, LOW);
    delay(delaytime);
    FPGA.digitalWrite(13, LOW);
    delay(delaytime);
    FPGA.digitalWrite(14, LOW);
    delay(delaytime);
    FPGA.digitalWrite(15, LOW);
    delay(delaytime);
    FPGA.digitalWrite(16, LOW);
    delay(delaytime);
  }
  for(delaytime=STARTDELAY;delaytime-=100;delaytime>0)
  {
    digitalWrite(LED_BUILTIN, LOW);   // turn the LED on (HIGH is the voltage level)
    delay(delaytime);
    digitalWrite(LED_BUILTIN, HIGH);    // turn the LED off by making the voltage LOW
    FPGA.digitalWrite(16, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(16, LOW);
    FPGA.digitalWrite(1, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(1, LOW);
    FPGA.digitalWrite(15, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(15, LOW);
    FPGA.digitalWrite(2, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(2, LOW);
    FPGA.digitalWrite(14, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(14, LOW);
    FPGA.digitalWrite(3, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(3, LOW);
    FPGA.digitalWrite(13, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(13, LOW);
    FPGA.digitalWrite(4, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(4, LOW);
    FPGA.digitalWrite(12, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(12, LOW);
    FPGA.digitalWrite(5, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(5, LOW);
    FPGA.digitalWrite(11, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(11, LOW);
    FPGA.digitalWrite(6, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(6, LOW);
    FPGA.digitalWrite(10, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(10, LOW);
    FPGA.digitalWrite(7, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(7, LOW);
    FPGA.digitalWrite(9, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(9, LOW);
    FPGA.digitalWrite(0, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(0, LOW);
    FPGA.digitalWrite(8, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(8, LOW);
  }
  for(delaytime=STARTDELAY;delaytime-=100;delaytime>0)
  {
    FPGA.digitalWrite(16, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(1, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(15, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(2, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(14, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(3, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(13, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(4, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(12, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(5, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(11, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(6, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(10, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(7, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(9, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(0, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(8, HIGH);
    delay(delaytime);
    FPGA.digitalWrite(8, LOW);
    delay(delaytime);
    FPGA.digitalWrite(0, LOW);
    delay(delaytime);
    FPGA.digitalWrite(9, LOW);
    delay(delaytime);
    FPGA.digitalWrite(7, LOW);
    delay(delaytime);
    FPGA.digitalWrite(10, LOW);
    delay(delaytime);
    FPGA.digitalWrite(6, LOW);
    delay(delaytime);
    FPGA.digitalWrite(11, LOW);
    delay(delaytime);
    FPGA.digitalWrite(5, LOW);
    delay(delaytime);
    FPGA.digitalWrite(12, LOW);
    delay(delaytime);
    FPGA.digitalWrite(4, LOW);
    delay(delaytime);
    FPGA.digitalWrite(13, LOW);
    delay(delaytime);
    FPGA.digitalWrite(3, LOW);
    delay(delaytime);
    FPGA.digitalWrite(14, LOW);
    delay(delaytime);
    FPGA.digitalWrite(2, LOW);
    delay(delaytime);
    FPGA.digitalWrite(15, LOW);
    delay(delaytime);
    FPGA.digitalWrite(1, LOW);
    delay(delaytime);
    FPGA.digitalWrite(16, LOW);
    delay(delaytime);
  }
}