Stimulator Tool

© 2022-2023, Kevan Hashemi Open Source Instruments Inc.


User Programs


NOTE: This manual applies to the Stimulator Tool Version 3.9+, available in LWDAQ 10.6.2+.

[08-OCT-23] The Stimulator Tool controls our Implantable Stimulator-Transponders (ISTs). It is a component of our LWDAQ Software. The Stimulator monitors IST activity with the help of either a Neuroplayer Tool or a Receiver Instrument. The signals transmitted by an IST are identical to those transmitted by our other telemetry devices, such as our subcutaneous transmitters (SCT), head-mounting transmitters (HMT), and implantable inertial sensors (IIS). Only the IST, however, can respond to telemetry to commands. When we transmit commands to an IST, we use pulses of radio-frequency waves that are thousands of times more powerful than the telemetry signals transmitted by the ISTs themselves.

Figure: Stimulator Tool on MacOS. We specify a stimulus and a synchronizing signal sample rate in a row of entries near the top. The Devices are presented in an expandable device list. Each device has an identifier, its own control buttons, a channel number for its synchronizing signal, and its own version number and battery voltage. The text window reports transmissions and auxiliary messages. Green background on identifier means a stimulus is running. Red identifier letters means the synchronizing signal is active.

Each IST is equipped with a crystal radio that receives commands and an oscillator that transmits telemetry messages. We transmit commands to the IST with a command transmitter. We receive commands with a data receiver. See Set-Up for details. All command transmitters and all data receivers will provide a LWDAQ server for which the Stimulator Tool will act as a client. The Stimulator Tool needs to know the internet protocol (IP) address of the server. If the server provides several LWDAQ driver sockets, the Stimulator Tool needs to know which socket we are using. There are entries for both these values in the Stimulator Window. We select a particular IST with its identifier, or ID. The identifier is written on the body of the IST as a four-digit hexadecimal number. Upon command, the IST will carry out a stimulus. We specify the number of pulses, the length of the pulses, the pulse interval, the strength of the pulses, and whether or not the pulses should be random or regular.

We use the Start button to initiate a stimulus in a particular device. We use Stop to end the stimulus prematurely. We use Xon to start synchronizing signal and Xoff to end it. All ISTs will turn themselves off after a couple of minutes when there is no stimulus running, so pressing Xoff is not necessary. We also have Start_All, Stop_All, and so on to start the same stimuli in all devices, or stop stimuli in all devices, and so on.

The IST uses telemetry auxiliary messages to transmit single messages that acknowledge commands, announce their version number, announce their identifier, and provide battery voltage measurements. With Verbose checked, the Stimulator will report the details of every command we transmit and all responses it obtains from ISTs. The Stimulator uses the responses to set the identifier background green when a stimulus starts and set it to gray when a stimulus ends. It sets the identifier digits to red during a synchronizing transmission and to black at the end of a synchronizing transmission. It uses the responses to update the version number and battery voltage values.

Upon command, an IST will use a telemetry channel to transmit a synchronizing signal. The synchronizing signal embeds the state of the stimulus into our telemetry recording. Positive pulses show when the stimulus current is turned on. The height of the pulses tells us the stimulus current. The synchronizing signal is similar to an SCT signal in that is has a sample rate and an SCT channel number. We set the sample rate and the channel number in the Stimulator Tool. The Stimulator Tool allows us to specify the telemetry channel each IST will use, so that our synchronizing signals do not conflict with those of our other telemetry devices.

When the Stimulator Tool transmits an identify command, all ISTs that receive the command will transmit their identifiers. The ISTs will not transmit all at the same time, but instead will wait for a length of time proportional to their identifier, so that they do not collide with one another. To acquire these signals and auxiliary messages, the Stimulator Tool looks first for a communal Neuroplayer Tool, and looks second for a communal Receiver Instrument. By "communal" we mean that the tool or instrument has been launched within the same LWDAQ process as the Stimulator Tool. We can ensure that the Neuroplayer or Receiver is communal by launching them from the Stimulator Tool using the Neuroplayer or Receiver buttons.

The simplest way to start communicating with a set of ISTs is to use the Receiver Instrument. We configure the Receiver Instrument to download, analyze, and display the live signals from a data receiver. The Stimulator Tool will look in this data for IST auxiliary messages. In any practical application of the IST, howevever, we will be recording biometric signals with a Neurorecorder. If so, we can monitor ISTs in real time by opening a Neuroplayer and playing the telemetry recording as it is written to disk. When we want to re-examine our stimuli and the effect they had upon simultaneous biometric signals recorded by our telemetry system, we use the Neuroplayer to play back the telemetry recording. The Stimulator Tool will report on the start and stop times of the signals using the time of the recording. Note that the Stimulator Tool will look for a Neuroplayer Tool first and a Receiver Instrument second. If it finds a Neuroplayer Tool, it will ignore any existing Receiver Instrument.

Figure: Synchronizing Signal and Stimulation Artifact. Pink: synchronizing signal transmitted by 0x6EEA. Blue: stimulation artifact in SCT in same beaker of water.

We can initiate stimuli by pressing buttons in the Stimulator Tool, but we can also initiate them by executing the stimulus command in response to an event we detect in one of our telemetry signals. By this means, we can implement closed-loop control. The Neuroplayer's Event Classifier can detect events, call an event handler, and so initiate a stimulus. If we want to respond to events that span several intervals, we enhance the event handler so that it becomes a state machine. Three consecutive seconds of electroencephalogram (EEG) identified as "ictal" might cause us to initiate a stimulus automatically. The event handler called by the Event Classifier would look something like this:

LWDAQ_post "Stimulator_start 3C54"

The above command initiates the stimulus defined in the Stimulator Window. If we want to define the stimulus in our event handler, we can do so with:

set Stimulator_config(pulse_ms) "10"
set Stimulator_config(period_ms) "100"
set Stimulator_config(num_pulses) "10"
set Stimulator_config(current) "8"
set Stimulator_config(sps) "512"
set Stimulator_config(random) "0"
LWDAQ_post "Stimulator_start 3C54"

In addition to its built-in stimulus and synchronizing functions our implantable stimulators will run programs we write ourselves. We describe how we can write, upload, and run our own algorithms in the User Programs section below.


[19-SEP-23] The figure below shows the connections required by a telemetry system that combines ISTs and SCTs. We follow the SCT set-up instructions and add the command transmitter. At present, the only command transmitter we have available is the Command Transmitter (A3029C). The A3029C is a LWDAQ device, and so requires a LWDAQ Driver (A2071E) to act as its TCPIP interface. The A3029C also requires its own dedicated 24-V power supply to boost its transmit power. In the figure, we show an Octal Data Receiver (A3027) sharing an A2071E with an A3029C. There are three telemetry reception antennas and one command transmission antenna. In the future, we plan to integrate the command transmitter into our Telemetry Control Box (A3042) so that all antennas can function as both receivers and transmitters.

Figure: Implantable Stimulator and Subcutaneous Transmitter Connections for Stimulation Experiments.

Referring to the diagram, we have the following components. (1) The Stimulator, Neurorecorder, and Neuroplayer run on the data acquisition computer. (2) A local or global internet provides communication with the computer. (3) A LWDAQ Driver provides power and communication for the data receiver and command transmitter. (4) The driver receives power from a 24-V adaptor with local AC wall cable. (5) The command transmitter receives boost power from a 24-V adaptor with local AC wall cable. (6) Shielded CAT-5 cables provide LWDAQ power and communication connections. (7) The Octal Data Receiver picks up signals transmitted from the implanted stimulators. (8) The Command Transmitter transmits radio-frequency commands to the implanted stimulators. (9) The animals are housed in a faraday enclosure. (10) The command transmit antenna is a loop antenna just like the receive antennas. (11) The receive antennas are connected to coaxial cables. (12) Dozens of animals may live together in the same faraday enclosure and be part of the same implantable stimulator system, each with their own implanted device, or with an implanted SCT that performs only EEG transmission. (13) Feedthrough connectors allow use to bring cables into the faraday enclosure without allowing ambient noise and interference to enter. (14) Coaxial cable carries radio frequency signals. (15) BNC plugs and sockets. (16) RJ-45 plugs and sockets.

The Command Transmitter (A3029) plugs into a Long-Wire Data Acquisition (LWDAQ) and receives its own 24-V power to boost its transmit power. When you connect the boost power supply, its blue boost light will turn on. Without the boost power supply, it will operate, but with lower output power and therefore shorter effective range. The command transmitter works well with a Loop Antenna (A3015), the same type of antenna used to pick up data transmissions from implanted SCTs.

Figure: Stimulator Data Acquisition Architecture, Using Neuroplayer. Only the Neurorecorder writes to the disk file. Any number of Neuroplayers may read the files as they are written. Neuroplayer Tool No1 runs in the same process as the Stimulator Tool. The other Neuroplayers run in separate, independent processes.

Once we have our system hardware connected together, we download and install the latest version of LWDAQ. In the Tool menu, we select the Neurorecorder. A new window opens, providing an independent Neurorecorder. We use this program to record telemetry signals from our SCT system. The Neurorecorder writes these signals to files on disk in our NDF format. Only the Neurorecorder writes to the file on disk, and it runs in a process of its own on the data acquisition computer. We go back to our original LWDAQ process and select Stimulator from the Tool menu. The Stimulator Tool opens. We use its Neuroplayer button to open a Neuroplayer. We set the Neuroplayer up to play the data being written to disk by the Neurorecorder. We play the live data file. The Neuroplayer will display SCT signals as well as IST synchronizing signals. The Stimulator will find auxiliary messages transmitted by the ISTs in the live recording and report them to its own text window.


[19-SEP-23] To communicate with an IST we must know its identifier (ID). The identifier is a number between 0 and 65535. Instead of writing the number as a decimal value, we write it as a four-digit hexadecimal value. So the identifier could be "A123" or "7431". The latter may be confused with a decimal number, so we prefer to write "0xA123" and "0x7431", where "0x" means "hexadecimal". The identifier of each IST is written on a label on its body. We can discover the identifiers of all IST within range of our command antenna by transmitting an identify command and waiting for their responses. We press the Stimulator's Identify button and wait for identifier messages to appear in the text window, each message reporting an identifier. The identifier "0xFFFF" is a "wildcard" identifier. We can specify 0xFFFF either with "FFFF" in the identifier entry box of one of our devices, or we can use a "*" character. When we send commands with the wildcard identifier, all ISTs in range respond at the same time. We may find that we do not receive their acknowledgements because the acknowledgements collide.

We can compose a device list consisting of these ISTs and control them each with their own Start, Stop, Xon, and Xoff buttons. We prepare a list of ISTs with the Add_Device button. We enter our IST identifier. We can save the list to disk and load the list from disk. If we save a list and also save the Stimulator configuration, the Stimulator will read the list automatically the next time it starts up. We remove devices with the X button at the end of each device entry.

When an IST transmits a synchronizing signal, it must use an SCT channel. We can configure the IST to use channel number 1-254, except we cannot use any number for which the remainder is either zero or fifteen when divided by sixteen. Thus we can us 1-14, 17-30, etc. Our SCTs always ship with channel numbers no greater than 222, so we can choose channel numbers 225 and higher for our ISTs and be sure they will not collide with an SCT. We specify the synchronizing signal channel in the channel entry of each device in our device list.

The Stimulator Tool does not turn on its green stimulus indicator, or turn on its red synchronizing indicator, just because we press the Start or Xon buttons. The Stimulator Tool waits until it receives the acknowledgement of these commands before it adjusts the indicators. If an acknowledgement fails, the indicators will remain fixed. The IST uses auxiliary messages to acknowledge commands, transmit battery measurements, and announce its identifier and version number. Set the show_aux flag in the Configuration Panel to get the Stimulator Tool to show you all the auxiliary messages it finds. When an IST transmits an auxiliary message, it uses the lower byte of its identifier as its channel number. It may be that this channel number is the same as the channel number used for another telemetry signal, but any such ambiguity will be resolved through the use of multiple auxiliary messages and timing. The IST always transmits two auxiliary messages one after the other. The first message contains some information, such as a version number. The second acts as a confirmation, and also contains the upper byte of the identifier.

Not only do we get to choose the channel number of an IST's synchronizing signal, we also get to specify its sample rate. The sample rate can be anywhere from 128 SPS to 1024 SPS. We recommend you use sample rates that are an even power of two, but the IST will allow any sample rate, and will do its best to transmit at the rate you request. Press Xon to start the transmission and Xoff to stop. When the IST transmits its synchronizing signal, it twenty times more current than it when it is asleep. All ISTs will turn off their synchronizing signal automatically a few minutes after the end of a stimulus so as to avoid running down its battery.

We specify an IST stimulus with a number of pulses, a pulse length, a pulse interval, a current code, and a selection of regular or irregular pulses. The pulse interval is the average time between pulses. If the pulses are regular, the time between pulses will be equal to the interval every time. If the pulses are irregular, which we select with the Random button, the pulse will be delayed by a random amount of time within its interval, subject to the end of the pulse never overlapping the start of the next interval. Regular and irregular pulses have dramatically different frequency spectra, as shown below.

Figure: Fourier Transform of Regular (Left) and Random (Right) Stimulus. Stimulus is 10 Hz pulses, each pulse 10 ms. We take the tranform of the synchronizing signal, whish is HI when the stimulus current is on and LO when the current is off.

We specify the pulse interval and pulse length in milliseconds. A pulse length of 10 ms combined with an interval of 100 ms gives 10-ms pulses at 10 Hz. The length for the A3041 IST is 2 ms and the maximum is 2 s. The A3041's pulse interval may be anything from 5 ms to 512 s. The number of pulses can be anything from 0 to 65535. The current code determines the stimulus current. The A3041A has the following relationship between current code and current.

Figure: Stimulus Current versus Current Code for Several A3041A. Codes 0-2 generate no current. For linear plot see here.

The stimulus current is subject to the constraint that the IST has a maximum voltage it can apply to its stimulus leads, and these leads have some internal resistance also. The A3041A with 45-mm leads has total lead resistance 50 Ω and a stimulus voltage of 3.3 V. If we connect the stimulus leads to a blue LED with forward voltage 2.9 V, we will see 8 mA flowing into the LED. IF we connect the ends of the leads together, however, we will see whatever current the IST is set to deliver, which is anything from 0 mA to 10 mA in the case of the A3041A.

User Programs

[01-DEC-23] Our implantable stimulators permit us to upload a user program that the stimulator will execute with a fixed execution period. These programs are written in the OSR8 assembly language and run on the stimulator's embedded OSR8 microprocessor. The A3041's microprocessor's clock speed is 5 MHz, which means we can execute one hundred lines of assembler code in approximately 50 μs. The A3041 sets the execution period of the user program to 5.0 ms. By default, the user program will execute until the extinguish counter runs down. But if the user program itself prevents the extinguish counter from reaching zero, the program can run indefinitely.

Figure: Transmit Panel. The device number refers to a device in the main window device list.

We upload user programs to the IST using the Stimulator Tool's Transmit Panel. The Transmit Panel operates upon one of the devices listed in the main Stimulator window. We refer to this device by its index in the device list, not by its four-byte device identifier. The Transmit button in the Transmit Panel transmits a sequence of commands to the selected device. We specify these commands with decimal values 0-255 or with hex values 0x00-0xFF. This transmit function is what we use when we are debugging IST firmware.

The Browse button allows us to select a program file on disk. The Run button reads a user program from disk, calls upon the OSR8 Assembler Tool to assemble the program into OSR8 machine code, uploads the program to the selected IST, and starts the IST's synchronizing signal so as to begin executing the user program. The results of assembly are printed in the Transmit Panel's text window. The Halt button stops the program execution and the synchronizing signal. The Edit button opens the program file in a LWDAQ text editor.

A user program takes the form of an assembly routine ending with a return instruction. Here is the simplest possible user program.

ret              ; Return to calling process.

The simplest program does nothing. it returns to the calling process. It is the user program that the IST writes to the user program memory when it wakes up. That way, if we tell it to run its user program without first giving it a user program, nothing bad will happen.

Any user program that does more than just return must interact with the IST's control registers and variable memory. All constants and variable locations used by the main program will be declared at the top of IST's main program. The A3041's main program is ROM.asm. The address space of the embedded microprocessor is divided into five sections: variable space, stack space, user variable space, control space, and user program space. We present the A3041 memory map below.

0x0000-0x00FFVariable SpaceVariable locations for the main program.
0x0100-0x01FFStack SpaceMain program stack starts at bottom and goes up.
0x0200-0x02FFUser Variable SpaceVariable locations for the user program.
0x0400-0x07FFControl SpaceControl and status registers.
0x0800-0x0FFFUser Program SpaceUser program code.
Table: Address Space of the A3041 IST's Microprocessor.

The control registers do things like set the stimulus current, initiate radio-frequency transmission, tell us when a command is ready, and allow us to read command bytes from the ITS's command receiver. Some of these registers can be written to and read back, but most are either write-only or read-only. The mmu_it3p location, for example, is write-only. It contains the interrupt timer period that governs how often the user program will be executed. The interrupt timer runs at 32.768 kHz and the A3041 sets mmu_it3p to 33, so the user program runs every millisecond. The main program provides two locations in its own variable space for the user program: the UPrun and UPinit flags. Both flags are set when the user program runs for the first time. The UPrun flag tells the IST to stay awake for the user program. The UPinit flag is for the user program to set to zero after it has performed its initialization, so that initialization will not be performed again.

Here is a program that transmits the IST extinguish counter as an SCT message. The extinguish counter decrements to zero, and when it reaches zero, the IST turns off. Any time we send a command to the IST, the extinguish counter resets.

; Example IST User Program. Transmits extinguish counter.
ld A,(0x001A)    ; Read low byte of extinguish counter
ld (0x0409),A    ; and load into transmit low byte.
ld A,(0x0019)    ; Read high byte of extinguish counter
ld (0x0408),A    ; and load into transmit high byte.
ld A,65          ; Write a channel number
ld (0x040A),A    ; to transmit register.
ld A,0x01        ; Write transmit code to
ld (0x040B),A    ; transmit control register.
ld A,50          ; Delay for ten microseconds
dly A            ; while transmit completes.
ret              ; Return to calling process.

Here we have all addresses hard-coded. But we could define the addresses with constants, as they are in the main program. When a user program needs variables, it has its own user program variable space. In the A3041, the user program has 512 bytes it can use for flags, numbers, pointers, and arrays. Our template user program, UProg.asm includes all the constants and variables defined in the P3041A, v1.9 main program, and executes some simple functions. The following program uses some of constants declared in the main program. The program turns on the stimulus current when the program first executes, waits for a fraction of a second, turns off the stimulus current, and clears the user program run flag so the device can go to sleep.

const mmu_stc  0x0406 ; Stimulus Current
const UPrun    0x0022 ; Running
const UPinit   0x0023 ; Initialize
const cntr     0x0200 ; Counter variable

ld A,(UPinit)     ; Check the initialization
add A,0           ; flag to see if we are 
jp z,initialized  ; starting or running.

ld A,0            ; Clear the initialization
ld (UPinit),A     ; flag.
ld A,8            ; Turn on the 
ld (mmu_stc),A    ; stimulus current.
ld A,255          ; load our counter
ld (cntr),A       ; with starting value.
ret               ; Return to main program.

ld A,(cntr)       ; Decrement our 
dec A             ; counter
ld (cntr),A       ; and if zero,
jp z,done         ; jump to done.
ret               ; Otherwise return.

ld A,0            ; Turn off stimulus
ld (mmu_stc),A    ; current and clear
ld (UPrun),A      ; run flag.
ret               ; Return to main program.

In the program, above, we use address labels "initialized" and "done" to implement our conditional statements. The assembler must resolve these labels into absolute addresses in the IST's program memory. The IST itself loads user programs into the correct location in memory, but in order for the assembler to resolve the labels, we must tell it the base address of the user program. The Base Address specifies the base address the assembler should use. In the P3041A v1.9 firmware, the program base address is 0x0800, and programs can be up to 2 KByte long. In the program below, we ramp up the stimulus current and drop it to zero again with a period of 255 × 5 ms = 1.3 s.

const mmu_stc  0x0406 ; Stimulus Current
const cntr     0x0200 ; Counter variable
ld A,(cntr)       ; Increment our 
inc A             ; counter and
ld (cntr),A       ; store.
srl A             ; Shift right
srl A             ; a total
srl A             ; of four 
srl A             ; times.
ld (mmu_stc),A    ; Set stimulus current.
ret               ; Return to main program.

Version Changes

Here we list changes in recent versions that will be most noticeable to the user.