We built the dynamic clamp system around the Teensy 3.6 microcontroller because, compared to alternatives of its class and price range, it is faster and has more memory. However, it is important to note that other microcontrollers could be used in its place. In particular, microcontrollers that can be programmed using the Arduino integrated development environment (IDE) require only small modifications to the code. There are many microcontrollers like this because Arduino has emerged as a standard in the community.
To demonstrate this point, we describe in this document how to use an Arduino Due or a chipKit uC32 in place of the Teensy 3.6. Neither is the equal of the Teensy 3.6 in speed or memory, but both are plausible alternatives. The code for both alternatives is archived with the rest of the software for this project at the public repository Github (https://github.com/nsdesai/dynamic_clamp).
A. Arduino Due
The Arduino line of microcontrollers includes many products (www.arduino.cc). At this writing (08/26/17), the product best suited to the dynamic clamp technique is the Arduino Due (clock speed 84 MHz, 512 kB flash memory, 92 kB SRAM memory). It includes 12 ADC inputs and 2 DAC outputs.
In the folder dynamic_clamp_arduino_due, we have modified the dynamic clamp code to work with the Arduino Due.
Main file. The main file differs from that of the Teensy main file in only two ways. (1) The pin connections have different names. The first DAC output of the Due is called “DAC0” whereas that of the Teensy is “A21”. The EPSC trigger pin we use for the Due is number 13 rather than number 2. (2) To keep track of time, we use the built-in Arduino functions millis() and micros() rather than the data types elapsedMillis and elapsedMicros. The latter types are also available for the Due but using them requires installing a separate library. Of course, this is simple to do but we chose instead to illustrate how to use millis() and micros() in place of the elapsed time data types; both methods work with the Teensy 3.6.
Tabbed (conductance) files. The Teensy has a floating point unit (FPU). To instruct the compiler to use the FPU, one uses special functions that end in the letter f in place of standard functions. One uses expf() to calculate an exponential rather than exp(); one uses sinf() to calculate the sine rather than sin(). The Due does not have an FPU. To make the code compatible with the Due, we simply removed the letter f – that is, we replaced the special FPU functions with the standard functions.
One other thing to keep in mind when using the Due: although the DAC outputs are nominally 3.3 V, they do not cover the full range between 0 V and 3.3 V. Instead they only cover the range 0.55 V to 2.75 V. The output calibration parameters (slope and intercept) will therefore be different from what one would have calculated using a Teensy.
B. chipKit uC32
chipKit is a line of microcontrollers based on Microchip Technology’s PIC32 microcontroller chip (chipkit.net). Even though it is not an Arduino product, it can still be programmed using the Arduino IDE.
One nice thing about the chipKit uC32 is that there is an add-on called Analog Shield (http://bit.ly/2wehEpp) available for it. This add-on allows the uC32 to read and write voltages between -5 V and +5 V directly. This means that users will not need to build the differential amplifier parts of the system (parts 2 and 4 of Fig. 1B of the main text). Of course, this convenience comes at a price ($50 as of this writing).
In the folder dynamic_clamp_chipKit_uC32, we have modified the dynamic clamp code to work with the chipKit uC32.
Main file. In addition to the two changes that apply to the Arduino Due (pin connections with different names; using millis() and micros() instead of the elapsed time data types), the uC32 main file must be modified in other respects to take advantage of the Analog Shield. (1) At the top of the file, we include two necessary libraries (analogShield.h and SPI.h). (2) The functions analogRead() and analogWrite() are replaced by analog.read() and analog.write(). (3) The ADC inputs and DAC outputs of the Analog Shield are 16 bit rather than 12 bit. So the calibration numbers are all different from those for the Teensy and the output is constrained to be less than 65536 (= 2^16) rather than less than 4096 (= 2^12).
Tabbed (conductance) files. As in the Arduino Due case, we must remove the letter f because the uC32 lacks an FPU.
The code for this alternative is archived with the rest of the software for this project at the public repository Github (https://github.com/nsdesai/dynamic_clamp).
We used the open-source environment Processing (www.processing.org) to control the Teensy microcontroller. Processing is useful because it is free and platform independent. However, many alternatives exist and these may be especially attractive to researchers who use other programs to acquire patch clamp data. All that is required is that the program can send a list of numbers to the microcontroller through the USB port.
One possibility is Matlab, which has an extensive user base in the neuroscience community and for which free electrophysiology software is available (e.g., wavesurfer.janelia.org or clm.utexas.edu/robotpatch).
In our example software, the Teensy microcontroller waits to receive eight numbers through the USB port. The eight numbers represent the values of (1) shunt conductance (g_shunt in nS), (2) HCN conductance (g_HCN in nS), (3) sodium conductance (g_Na in nS), (4) excitatory Ornstein-Uhlenbeck (OU) mean conductance (m_OU_exc in nS), (5) excitatory OU diffusion constant (D_OU_exc in nS2/ms), (6) inhibitory Ornstein-Uhlenbeck (OU) mean conductance (m_OU_inh in nS), (7) inhibitory OU diffusion constant (D_OU_inh in nS2/ms), and (8) EPSC conductance (g_EPSC in nS). When the microcontroller receives these numbers, it changes the value of the conductances and diffusion constants appropriately.
Each number must be a byte array representation of single precision float point (4 bytes containing 32 bits). What this means is described here (https://en.wikipedia.org/wiki/Single-precision_floating-point_format). This topic can be somewhat arcane, but fortunately most languages have built-in methods to convert numbers from one type to another. For example, in Matlab, we can convert the number pi into a byte array using the function typecast like this:
>> pi = 3.141592653589793; % 64-bit representation
>> pi_single_precision = single(pi) % 32-bit representation
>> pi_byte_array = typecast(pi_single_precision,'uint8') % byte array representation
219 15 73 64
One can also go the other way: to convert the byte array back into a (32-bit) floating point, enter this line at the command prompt: typecast(pi_byte_array, ’single’).
In the Matlab script Matlab_simple_example.m, we show how to write eight conductance/constant numbers to the Teensy. Before using this script, users should change the serial port name (e.g., ‘COM3’) to the name of the USB port to which their Teensy is attached.
We also provide a Matlab graphical user interface (GUI) with which users can control the board. It has the same functionality as the Processing GUI. To use it, (1) save the two files (DC.m and DC.fig) in the Matlab current directory; (2) open DC.m and find the line “initializeteensy(‘COM3’)”; (3) change COM3 to the name of the USB port for your set-up; (4) save the file; and (5) open the GUI by typing “DC” at the command line. This will open up the GUI, which looks like this:
The sliders can be moved to select new values for the conductances and constants. Pressing Upload sends these values to the Teensy microcontroller. Pressing Zero zeroes all the values and sends zeros to the microcontroller (i.e., so that no dynamic clamp conductances are being simulated).