Rorden, C., & Hanayik, T. (2014). StimSync: Open-source hardware for behavioral and MRI experiments. Journal of neuroscience methods, 227, 90-99.
Many neuroscience experiments rely on presenting stimuli and measuring participants' responses to these events. Often computer screens, speakers and keyboards are sufficient. However, these devices are not appropriate for some situations. For example, some studies present tactile or olfactory stimuli or brain stimulation. Likewise, keyboard buttons are not appropriate for use with vocal responses, small animals or individuals with motor impairments.
We describe StimSync, which simulates USB keyboard inputs, allowing use with most experimental software. StimSync can measure button presses, optical signals from magnetic resonance imaging systems, changes in ambient light (e.g. synchronizing intracranial electrography), and auditory events (a voice key). In addition to the USB keyboard mode (necessarily millisecond precision), StimSync can also be set to provide higher precision timing. This feature can be used to validate timing, ensuring event synchronization (e.g. auditory events, visual events, brain stimulation). In addition to recording inputs, StimSync provides seven digital outputs for controlling external devices. Finally, StimSync can record analog inputs; we illustrate how this can be used to evaluate the rise time for computer displays.
We observed outputs with a mean latency of 2.1ms (sd=0.17ms) and USB inputs with a mean latency of 2ms (sd=0.54ms).
StimSync statistically outperforms two professional solutions and numerically outperforms other devices described in the literature.
StimSync (http://www.mccauslandcenter.sc.edu/CRNL/tools/stimsync) provides an open-source solution for controlling and validating neuroscience experiments. In addition to sharing the design, we have produced a batch of devices to demonstrate the market for professional implementations.
Important note: Windows may not recognize a Teensy as a serial device when you plug it into a Windows computer. In this case, you should install the "Windows XP/Vista/7 Installer" (to reprogram the Teensy) or the "Windows Serial Installer" (to connect to a pre-programmed Teensy) from http://www.pjrc.com/teensy/td_download.html. On OSX computers, the serial port should be detected automatically, but you will want to get the Teensyduino software for programming.
Here are a few programs for using the Arduino as an Oscilloscope For details visit http://www.mccauslandcenter.sc.edu/CRNL/tools/oscilloscope
1.) ARDUINO: stimsyncArd This is the sketch you need to load onto the Arduino/Teensy. It will mimic a keyboard, a microsecond timer or an oscilloscope depending on the software you run. This software works well on Teensy 3, Teensy 2, Arduino Leonardo. The code will install in the Arduino Due, but there are several issues: the Due has no EEPROM so you can not create new key mapping, the Due oscilloscope timer has not been well tested, the Due can send data to either the native USB port OR the Bluetooth port (serial1) - so you need to decide at compile time if you want a wired or wireless connection (Teensy devices support both simultaneously). To install a.) Launch Arduino software that supports your device. Teensy 3 users should get the latest version of the Teensyduino software from http://www.pjrc.com/teensy/beta/ b.) Use File/Open to open stimSyncArd sketch c.) Select your device type in Tools/Board, e.g. Tools/Board/Teensy3 - if your device type is not listed please get the correct Arduino/Teensyduino software d.) Select correct port from Tools/SerialPort, e.g. usbmodem12345 e.) For Teensy devices, make sure Tools/USBtype is set to Serial+Keyboard+Mouse+Joystick f.) Adjust the first few lines of code in stimsyncArd so that You will need to comment in/out the first couple lines for your device, for example if you have a Teensy 2, remove the "//" in front of the line IS_TEENSY2 and make sure the other "IS_" lines have a "//" at the start.
2.) ARDUINO: Bluetooth_Programmer_Ard use the Arduino to reprogram a JY-MCU bluetooth device to operate a 921600bps instead of the default 9600bps. You only need to run this once to reprogram your bluetooth card. This allows much faster wireless communication. This is only required if you want a wireless oscilloscope, otherwise the USB cable can be used. 3.) LAZARUS: OsciLaz is a simple oscilloscope for Lazarus that can be natively compiled for OSX and PC. You can change the sample rate, number of channels and save data in brain vision analyzer format (for analysis with EEGlab, ELEcro, etc). 4.) LAZARUS: keymapLaz allows you to change the keyboard mapping when you device is not operating as an oscilloscope. The Arduino will appear as a USB keyboard 5.) MATLAB: ScopeMath_Arduino This is a simple oscilloscope for Matlab. You can change the sample rate, number of channels and save data in brain vision analyzer format (for analysis with EEGlab, ELEcro, etc). 6.) PROCESSING: osciProcessing This is a simple oscilloscope for the Processing language. You can change the sample rate and number of channels. 7.) XCODE: osciXcode This is a simple oscilloscope for the Xcode language (with a compiled OSX program). You can change the sample rate and number of channels.
The Arduino should be configured as follows: A0..A6: these are the analog inputs that will be read by the Oscilloscope. For example, if you wish to record the position of a knob on the first channel (A0), place a 10k potentiometer so that one side is attached to the Arduinos ground, the middle wiper is connected to A0 and the other side is connected to the maximum analog voltage (5v for Uno and Teensy 2; 3.3v for Leonardo and Teensy 3). pin 0 and pin 1 can optionally be used for bluetooth (wireless) communication. For example, the JY-MCU device needs to have ground (gnd) attached to the Arduino GND, the 3.6-6v attached to the Arduino 5v, the RXD attached to the Arduino TX (pin 1) and the TXD attached to the Arduino RX (pin 0). pins 2..9 can be used to connect digital signals (momentary switches or electrical pulses). For example, if a momentary switch has one side attached to the Arduino ground (GND) and the other side attached to pin 2, every time pin 2 is depressed a signal will be recorded on the Arduino digital channel (which you can see on the Matlab trace and will be saved to the brain vision file). These digital signals allow you to time-stamp events pin 13 (pin 11 on the Teensy 2) controls the on board light - it will blink when the device is in oscilloscope mode the remaining pins can be optionally used as digital outputs.
Software Description The microcontroller is programmed with an Arduino ‘sketch’ which is uploaded into the microcontrollers’ persistent memory. Therefore, this step only needs to be done once. The sketch includes definitions for the different devices we support, so the single source code can program devices with different types of CPU (e.g. AVR and ARM processors use different interrupt calls) and different numbers of analog inputs (e.g. the Teensy 3 has 14 analog channels whereas the Leonardo has 6). Serial communication between the computer and the microcontroller is via a USB or Bluetooth based serial port. We refer to the three types of signals sent between these devices as commands, sampling packets and digital out signals. We describe this simple and extensible open format below. All two byte values refer to unsigned little-endian 16-bit integers. Our goal was to allow any computer to dynamically set the desired sample rate and number of channels for any microcontroller running our sketch. The computer can change and query the microcontroller settings with commands that are 4 bytes long. These four bytes define the Action (1 byte), Property (1 byte) and Value (2 bytes) for the instruction. The first byte is defines the ACTION, which is either SET (177) or GET (169). A SET action changes the microcontroller setting, whereas the microcontroller responds to a GET command by reporting its current setting. The three relevant properties for EMG recording are HZ (132), SUPERSAMPLE (136), CHANNELS (133), and MODE (163). The HZ property refers to the rate at which samples will be reported. The SUPERSAMPLE property allows the data to be measured faster than reported, which we describe in more detail below. The CHANNELS property refers to the number of analog channels to be recorded. The MODE is used to switch the data measurement and streaming on and off. For example, to begin a recording of 10 channels at 100 Hz, one could issue the commands SET:HZ:100 (177,132,0,100), SET:SUPERSAMPLE:0 (177,136,0,0), SET:CHANNELS:10 (177,133,0,10), GET:CHANNELS (169:133,0,0) and SET:MODE:OSCILLOSCOPE (177,163,162,162). At this point the microcontroller will begin reporting samples 100 times per second until told to stop, for example with a SET:MODE:KEYBOARD (177:163:169,169 – putting the microcontroller into a keyboard emulator mode). The order of commands is generally not important, with the exception of the MODE command being the final command before starting the sampling. In this example we illustrate the optional use of a GET:CHANNEL command after a SET CHANNEL command. If all is well, the microcontroller will respond with a GET:CHANNELS:10 (169:133:0:10), denoting 10 channels are available. This is good coding practice, as for example an Arduino with only 6 channels will respond 6, warning the computer that it can not provide as many channels as requested. Likewise, a device that is not running our sketch will not provide this response. Therefore, this GET command is useful for ensuring that the hardware is available to support the desired acquisition. While in the oscilloscope mode, the microcontroller sends data in the form of sample packets. These packets are 4+2*N bytes long, where N is the number of analog channels. Each packet begins with a byte that has the most significant bit set to zero (distinguishing packets from commands). The rest of this first byte can either be ignored by the computer or decoded to provide the timing information as we describe next. The next three bits signify the sample number, which loops from zero to seven. This sample number allows the computer to detect missing packets and also allows it to decode the microcontrollers’ time stamp, which is stored in the least significant four bits of this first byte. Once every 8 samples (sample number 0) the microcontroller records its clock time in milliseconds as a 32-bit unsigned integer. Sample number 0 will report the most significant bits (31..28) of this value, sample number 1 reports the next bits (27..24), etc. This timestamp can optionally allow the computer to detect drift between its own clock and that of the microcontroller (though the computer should be aware of that the Arduino millis() function overflows back to zero every ~50 days). The next two bytes provide the status of the Arduino’s seven digital outputs (high byte) and eight digital inputs (low byte). This digital channel allows precise time stamping of events. Next, a two-byte integer is reported for each channel. The final byte of a packet is a checksum, allowing error detection that is particularly important for wireless communication. The checksum is simply the sum of all previous bytes in the packet folded into a single byte (in the Arduino language this folding is done like this: “while (checkSum > 0xff) checkSum=(checkSum >> 8)+(checkSum & 0xff);”). The final communication between the computer and the Arduino is the digital out signal. This is a single byte, with a value less that 128 which sets the status of the seven digital output bits. Note that the first two bytes of any command each always greater that 128, providing a unique signature for discriminating commands from digital out signals. For example, in Matlab where serialPort is an open port connection with the Arduino, the command “fwrite(serialPort,126);” would switch off the first ouput and turn on the other six. These digital outputs allow the computer to control external stimuli. Each digital output can only provide 9.4mA at 3.3v – this is sufficient to switch a light emitting diode, and enough to switch a solid-state relay if more power is required. In addition, this power is sufficient for an opto-isolated transistor, which would be the recommended way to trigger a TMS system (so there is no electrical connection between devices). As noted previously, the status of the digital outputs is echoed in the sample packets, allowing data to be segmented based on these events. In sum, we define three types of communication: commands, sample packets and digital out signals. The computer sends both set and get commands as well as digital out signals to the microcontroller. The microcontroller reports get commands and sample packets. Each command is initiated with an initial byte that has a value greater than 127, distinguishing commands from the other types of communication. Sample packets provide check sums. This robust scheme allows the user to quickly establish the range for wireless communication. This format is very scalable – in theory any sampling rate from 1 to 65,535 Hz and any number of analog channels from 1 to 65,535 can be specified and transmitted (though support for these software features will be limited by the hardware). Our software allows the user to specify a supersampling rate, where the signals are measured much faster than they are reported, with the report averaging across the prior sub-samples. For example, consider scalp EEG recording, where the impedance of the skull effectively limits the frequency of any brain activity. In this case, there is no meaningful signal beyond 200 Hz (fast enough to effectively remove 60 Hz electrical line noise). However, one might plausibly sample at a higher rate (e.g. 800 Hz) and average this data in order to minimize measurement noise. Our software allows this averaging to be done by the Arduino, reducing the communication bandwidth and the disk storage requirements. This can be particularly useful for devices with very limited communication speeds, such as the Arduino Uno that is effectively limited to reporting one channel at around 100 Hz. Supersampling can also be useful for TMS-compatible EMG, as the TMS pulse generates a very large amplitude but exceptionally brief duration spike of around 300 µs (Veniero et al., 2009). Therefore, even a 2000 Hz sampling rate might miss this signal. By supersampling, this event can be reliably detected. Therefore, prior to recording the user can specify a supersampling exponent e from 0 to 15, with the hardware acquiring 2^e subsamples per reported sample. For example, if the user specifies a 100 Hz recording with e=3, then the Arduino will send 100 samples per second based on the average of a 800 Hz (2^3) subsampling rate. In theory, according to the square root law the precision should be improved by the square-root of the number of samples averaged (e.g. in our example E=3 should provide 2.8 times the precision of the default E=0). Though note in practice much of the error may reflect system noise that will be highly correlated across subsamples. Further, it should be noted that the hardware places some limit on the maximum sample rate. Using a power of two allows the software average using efficient bit-shifting rather than computationally expensive division. It should be noted that raw data from devices with less than 16-bit precision (e.g. devices with AVR CPUs are limited to 10-bit analog to digital conversion) are scaled to 16-bit values, ensuring that the average preserves the maximum possible precision. It should be noted that when supersampling is enabled the mean sample time is slightly before the reported sample time, for example at 100 Hz sampling a high super sampling factor means the average sample occurred almost 5 ms before the sample was reported. We have created computer display applications for electrophysiological observation and recording in four different programming languages. This allows scientists and students to use the language that is familiar and available to them. Each of these samples allows the user to select the number of channels and sample rate. Each displays an oscilloscope style graphical display. These are all provided as open source, and are covered by the popular BSD license except as noted. Matlab is a very popular cross-platform scriptable language. Our Matlab application demonstrates how to control digital outputs, optionally display a power spectrum, and provides an option to save the data in BrainVision Analyzer format for offline analysis. This demo was derived from the ‘ScopeMath_Simple’ demo created by a Matlab employee, and is distributed with their permissive license. We note that the popular open-source EEGLAB (Delorme and Makeig 2004) is also written in Matlab and supports the BrainVision format, providing a useful combination for both acquisition and analysis. One caveat is that Matlab is a proprietary language. While the open source Octave language can run many Matlab scripts, it is not currently compatible with our software. XCode is a popular programming language for the Apple OSX operating system. Our sample application uses the open source AMSerialPort unit written by Andreas Mayer, Sean McBride and Pat O’Keefe. We use Apple’s CoreGraphic API to show images fluidly, and the displays can be saved as high-resolution PDF vector images. We include a simple display program in the Processing programming language. Processing builds on the Java language. The core language and integrated development environment are closely related to the native Arduino language. Therefore, this language is a good fit for this project. Processing sketches can run on multiple environments and the sketches can be compiled to run as native applications. Our sketch extends Sofian Audry’s simple oscilloscope sketch. In addition to specifying the number of channels and sampling rate, our software also provides the user with the ability to save the recorded data as tab-delimited text that can be explored offline in with spreadsheets and other software. Finally, we provide display and recording software using the Lazarus development environment and Free Pascal. This software can be compiled to run natively for Linux, Windows and OSX. The software shows both the most recent data as well as the data from the most recent trigger signal – for example a static display from the most recent TMS pulse as well as a continuously updated display of new samples. The user can select to display filtered data, removing both high and low frequency signals if desired. The raw data can be stored in BrainVision Analyzer format for offline analysis.