Obtaining and installing Arduino and Processing
The Arduino website is www.arduino.cc.
1) Download the Arduino software. The site offers an online IDE (called “Arduino Web Editor”), but we have not been able to get that to work with the Teensy 3.6. So stick with the standard IDE. At this writing (05/29/17), it is Arduino 1.8.2. This works with Windows, Mac, and Linux. Follow the installation instructions given by the Arduino site.
To allow Arduino software to communicate with the Teensy 3.6 microcontroller, we use an add-on called Teensyduino. Here is the website: https://www.pjrc.com/teensy/td_download.html.
Download Teensyduino (Windows, Mac, or Linux) and follow the installation instructions given by the site.
a) Attach the Teensy microcontroller to your computer through a USB port. Make note of the port name (on Windows, the name will be something like “COM3”; on Mac, something like “/dev/tty.usb3232”; on Linux, something like “ttyS3”.)
b) Open the Arduino software. From the Tools menu, make sure that the Board selected is the Teensy 3.6 and that the Port is the USB port to which you attached the Teensy.
To make sure everything is working properly, run the Blink program. This is like the microcontroller version of “Hello, world!” How to do so is explained here: https://www.pjrc.com/teensy/td_usage.html. (One correction: Blink can actually be found at File > Examples > Basic > Blink.) The page features a Teensy 2.0, which is physically smaller than the 3.6, but the process is the same. Note the location of the pushbutton on the Teensy 3.6. If the microcontroller ever behaves oddly, and especially if you’re not sure whether a program has successfully uploaded, try pushing the button; it acts like a hard reset.
Warning about anti-virus programs: There have been scattered reports on the forums at www.pjrc.com that some of the features of some anti-virus programs can interfere with Teensyduino. In particular, McAfee’s real-time scanning on Windows machines can prevent Teensyduino from installing properly and/or prevent it from uploading programs from the host computer to the microcontroller. If you experience such a problem, try turning off McAfee real-time scanning when installing Teensyduino or uploading a new program. The other parts of the McAfee program are fine, and once the installation or uploading is finished you can turn real-time scanning back on.
The Processing website is https://processing.org.
a) Download Processing. We have tested version 3.3.6 (current as of January 2018).
b) Open Processing. Add the ControlP5 library by selecting Sketch > Import Library … > Add Library …; searching for ControlP5; and installing it.
c) Add the grafica library by selecting Sketch > Import Library … > Add Library …; searching for grafica; and installing it.
For future reference, this is the ControlP5 website: http://www.sojamo.de/libraries/controlP5/.
You should already have installed Arduino and Teensyduino following the instructions given above.
Copy the folder dynamic_clamp (found in the Github repository: https://github.com/nsdesai/dynamic_clamp) to some place on your computer, such as the Arduino folder.
Find the main file dynamic_clamp.ino inside that folder and open it in Arduino. Make sure that your Teensy 3.6 is connected and recognized by going to the Tools menu. It should look something like this:
In our case, as you can see, the Teensy is located at COM7. Make note of the name of the USB port for your board.
Compile and upload the program to the microcontroller by pressing the right-facing arrow at the upper left of the window. It might take as long as a minute for the process to complete; be patient. The little window the Teensy opens up should flash “Rebook OK” if all has gone well. If you don’t see that (comforting) message, press the pushbutton on the Teensy (it is just in front of the microSD port); this will force an upload.
The program should now be on the microcontroller, and you can use the Processing GUI to control the dynamic clamp simulation (see Using_and_modifying_Processing_software).
Note that you need upload the program only once. It will remain on the microcontroller indefinitely.
Remember that all the code for this project is archived at the public repository Github (https://github.com/nsdesai/dynamic_clamp).
To modify the conductances or add new ones, you should understand the program structure. The program consists of multiple files. Opening the main file dynamic_clamp also opens the other Arduino files contained in the same folder. These appear in the tabs.
The main file consists of three parts: (1) global variables, (2) setup function, and (3) loop function.
(1) Global variables
These are variables accessible to all functions. The only ones that users are likely to wish to change are the ones that determine how the electronic circuits are calibrated.
We describe how to set these numbers under the Calibration tab.
Note that the global variables include all the conductance values (e.g., g_shunt, g_HCN, g_Na).
(2) Setup function
The setup function is run once, when the program is uploaded to the microcontroller. It mostly involves housekeeping functions (initializing the serial port to communicate with Processing or whatever program will set the conductance values, specifying the analog resolutions, specifying which pin is to be used when triggering EPSCs). It also calls the functions that generate the lookup tables used by several of the conductances; these functions are contained within the (tabbed) files that define those conductances.
The use of lookup tables (see, for example, https://en.wikipedia.org/wiki/Lookup_table) is a common tactic in real-time systems. Rather than doing calculations at runtime, one pre-calculates numbers for a wide range of parameters and then simply looks up the number for a given parameter when it is needed. This can save a lot of time. In the case of Hodgkin-Huxley-style conductances, one pre-calculates the steady-state values and time constants of gating variables for a wide range of membrane potentials. At every time step, rather than doing the calculation again, one finds the pre-calculated steady-state value and time constant most closely corresponding to the measured membrane potential and uses them in subsequent operations. Again, looking up numbers in a saved list tends to be much faster than doing calculations.
(3) Loop function
Every Arduino sketch contains a loop function. It is run constantly (i.e., at every time step).
Our loop function contains three parts. The first part checks the USB port for a serial communication instructing the microcontroller to change the values of the various conductances. Whenever the port receives 32 bytes (4 bytes for each of the eight expected numbers), the conductance values are updated.
The second part reads the membrane potential (using the calibration parameters to map the measured analog input into the neuron’s membrane potential) and uses this to calculate the current the dynamic clamp conductances should inject. It does this by calling the functions of all the active dynamic clamp conductances.
The third part transforms the total dynamic clamp current into an output to be sent through the Teensy’s analog output (DAC) (using the calibration parameters). Note that these numbers are limited to the range 0-4095 (12 bit).
Each tabbed file contains the specifications for a single conductance. If you wish to modify any given conductance, this is the only file that you need change.
As an example, consider the transient sodium conductance. The code is reproduced here.
There are three sections.
The first simply declares arrays in which to store the activation and inactivation parameters of the Hodgkin-Huxley formulation: αm, βm, αh, and βh (Johnston and Wu, 1994). Each of these is a function of membrane potential Vm. We assumed that only the potentials between -100 mV and +50 mV were likely to be important, and that 1 mV precision was sufficient. So each array stores 151 numbers (one for each millivolt between -100 and +50).
Declaring the array variables simple assigns them a place in memory, it doesn’t fill in their values for different values of Vm. That is instead done by the second section, the function called GenerateSodiumLUT. This function is called by the setup function of the main file when the program is first uploaded to the board. There are three things you should note about this function. (1) The arrays are indexed beginning at 0, so that the first element of the array alphaM is alphaM and its last element is alphaM. The corresponding voltages are 100 less than the index number; that is why the line “v = (float)x – 100.0;” is there. Also, the (float) part simply converts the integer x into a floating point (32-bit number with a decimal point). (2) Rather than use the function exp(A) to exponentiate an argument A, we instead use the function expf(A). The difference is that expf explicitly tells the compiler that its argument will be a 32-bit floating point number, as opposed to some other data type, and to use the Teensy’s built-in floating point unit (FPU) for the calculation. If we had instead used exp, the compiler might have failed to take advantage of the speed enhancement the FPU offers for calculations involving floating point numbers. For the same reason, you should always use math functions that end in f over those that do not when using the Teensy (sinf rather than sin, cosf rather than cos, sqrtf rather than sqrt). See, for example, this web page: https://tympan.org/2017-02-09-for-speedy-float-math-specify-float/. (3) When the index x =60, the voltage equals -40 mV. This is problematic for the Hodgkin-Huxley function αm. If you simply plug in Vm= -40 mV, the numerator goes to zero but so does the denominator. The ratio 0/0 is ambiguous, though inspecting the function on either side of -40 mV indicates that it should equal 1. That is why the if-else statement is there: to ensure αm equals 1 when Vm= -40 mV. You should always be aware of potential problems like this. For example, if a function expf(a/b) appears in a denominator and there’s any chance that b will ever get close to zero, it is better to write this as expf(a) – expf(b).
The third section is the function Sodium(v) that calculates the sodium current on every time step. It involves the activation and inactivation gates mNaVar and hNaVar. These are integrated using the forward Euler method. This is a simple integration method, but as long as the time step dt is small (and here it is quite small compared to the kinetics of the sodium gates), the method is sufficient. Nearly every previous dynamic clamp implementation used forward Euler. Here too there are three things worth noting. (1) We convert the voltage (-100 to +50 mV) back into an index (vIdx) by adding 100 – just as we subtracted 100 in GenerateSodiumLUT. (2) We use if statements to make sure that mNaVar and hNaVar always stay non-negative. (3) We use the built-in function constrain() to make sure that vIdx always stays between 0 and 150 regardless of the value of membrane potential.
Using the Processing software
You should already have installed Processing following the instructions in the section of this page Obtaining and installing Arduino and Processing.
The Processing program is in the folder processing_control. It consists of a single file called processing_control.pde. Open it by double-clicking.
Find the line that reads: “myPort = new Serial(this,”COM7″,115200);” and change COM7 to the name of the USB port to which you attached the Teensy microcontroller. Save the revised file.
Press the run button (right-facing arrow at upper left) in the Processing window.
This opens up a graphical user interface that looks like this:
The eight parameters that can be changed during an experiment are the ones specified in the main text. All of the conductances are in nS; all of the diffusion constants are in nS2/ms.
When the Processing applet is first run, all the numbers are set to zero. To change them, use the sliders to move to the desired values and the press the Upload button at the bottom left.
For example, to change the shunt conductance to 5.00 nS and the HCN conductance to 2.99 nS, the window should look like the picture below. When you press Upload, the button will be briefly highlighted. The numbers will be sent by Processing to the Teensy microcontroller and the new conductance values will take effect immediately.
Subsequently pressing the Zero button will zero all the numbers and return the microcontroller to its initial state.
Modifying the Processing program
In the section Adding a potassium M conductance, we describe both how to code the conductance in the Arduino program and to add it to the Processing program. That should serve as a good example of how to add other types of conductances.
Of the existing conductances, the only things users are likely to wish to modify the minimum value, maximum value, and default value. These are set in the setup() function. For example, in the case of the sodium conductance, look for this line:
dcControl.addSlider(“g_Na”, 0, 200, 0, 100, 150, 200, 30);
The control is explained at this web page http://sojamo.de/libraries/archive/controlP5-0-3-14/reference/controlp5_method_addslider.htm. In particular, the first argument (“g_Na”) is the name of the control, the second (0) is the minimum value, the third (200) is the maximum value, and the fourth (0) is the default value. The other four numbers control the x position, y position, width, and height of the slider.
We wish to add a potassium M conductance to the dynamic clamp system. The conductance we have chosen is one that appears in Fransen et al., J. Neurosci. (2002). The conductance is modeled in the Hodgkin-Huxley way by a single activation gate:
Here, represents the fraction of open M channels at an instant in time t. Its steady-state value depends on membrane potential Vm:
So does its time constant:
This is what they look like:
The current this conductances passes is given by:
where gM is the maximal M condutance (in nS) and is the potassium reversal potential (-80 mV).
Modifying the Arduino program
To add this conductance to the Arduino program, we have to do two things: (1) add references to the M conductance to the main file dynamic_clamp.ino, and (2) add a tabbed file defining the conductance.
Open the dynamic clamp program in Arduino.
(1) Add the maximal M conductance to the list of global variables in the first section.
Note that we both changed the number of parameters (nPars) to 9 and added the last line declaring and setting its initial value to 0.0
(2) In the setup() function, add a call to a function GenerateMLUT() that will create lookup tables of values of and for a wide range of membrane potentials. Rather than doing the calculations at every time step, we will simply look up the appropriate values for the measured , thus allowing the program to execute more quickly.
The function GenerateMLUT() will be defined in the tabbed file we will create shortly.
(3) Add the maximal M conductance gM to the list of parameters the Teensy receives over the USB port from the Processing sketch.
(4) If gM>0, have the simulated M current added to the other simulated currents. If it equals 0, then we don’t bother since the current will simply be zero.
Now we create a tabbed file that defines the M conductance.
(1) Create a new file. In the Arduino window, look for the downward-facing arrow (indicated by the red arrow). Click it and select “New Tab”. You will then be asked to name the new tabbed file – just call it “M”.
(2) In that M file, enter the three parts shown below: (i) array declaration in which the lookup table values of minf and τm will be stored; (ii) the function GenerateMLUT() that generates the lookup tables (for membrane potentials between -100 mV and +50 mV); and (iii) the function that numerically integrates m(t) and calculates the M current at every time step.
A few things to note. (1) We use the function expf() in preference to exp() because the former instructs the compiler to make use of Teensy’s floating point unit (FPU), thus speeding up the calculations. (2) We use the built-in function constrain() and an if statement to make sure vIdx and m_Var stay within bounds. These lines aren’t strictly necessary because an out-of-bounds situation may never arise, but better safe than sorry. (3) We use the forward Euler method to integrate , which is called m_Var in the code. The time step is short enough (compared to the kinetics of the M conductance) that this is acceptable.
Finally, save the modified program and upload it to the microcontroller by pressing the right-facing arrow at upper left.
III. Modifying the Processing program
To modify the Processing program (processing_control.pde) so that it will specify the maximal M conductance gM in addition to the other parameters it already specifies, we need only add four lines.
(1) Add gM to the list of variables declared when the GUI opens.
(2) Add a slider with which to specify the value of gM.
(3) Add a statement to write the value of gM to the Teensy microcontroller through the USB port.
(4) Add gM to the list of variables zeroed out when the user presses the Zero button.
Save the changes and then run the Processing program. It should open up a GUI window that looks like this:Notice that a slider for the M conductance has been added to the end. It can be used just as the others are.
Notice that a slider for the M conductance has been added to the end. It can be used just as the others are.
The completed Arduino and Processing programs, with the changes specified in this document, can be found in the folders called dynamic_clamp_with_M and processing_control_with_M.