├── 1-click_BOM.tsv ├── 3D print ├── Spikeling LED holder.3mf ├── Spikeling LED holder.scad └── Spikeling LED holder.stl ├── Arduino ├── Spikeling │ ├── Definitions.h │ ├── Mcp23s18 │ │ ├── Mcp23s08.cpp │ │ ├── Mcp23s08.h │ │ ├── SPI.parameters.h │ │ ├── gpio_expander.cpp │ │ ├── gpio_expander.h │ │ └── keywords.txt │ ├── README.md │ ├── SettingsArduino.h │ ├── SettingsESP.h │ └── Spikeling.ino └── Spikeling_ploter │ ├── Definitions.h │ ├── SettingsArduino.h │ ├── SettingsESP.h │ └── Spikeling_ploter.ino ├── Bill of Materials (BOM).xlsx ├── Example recorded data.zip ├── LICENSE ├── MATLAB scripts ├── spikelingFunctions - Kernels.m └── spikelingFunctions.m ├── PCB ├── Spikeling PCB.b#1 ├── Spikeling PCB.brd ├── Spikeling PCB.pdf ├── Spikeling PCB.pro ├── gerber.zip └── gerbers │ ├── B.Cu.gbr │ ├── B.Mask.gbr │ ├── B.Paste.gbr │ ├── B.SilkS.gbr │ ├── F.Cu.gbr │ ├── F.Mask.gbr │ ├── F.Paste.gbr │ ├── F.SilkS.gbr │ ├── drills.xln │ ├── gerber_job.gbrjob │ └── profile.gbr ├── Python Script └── Spikeling Analysis.ipynb ├── README.md ├── Serial Oscilloscope (PC).zip ├── Spikeling manual and exercises.docx ├── Spikeling manual and exercises.pdf ├── kitspace.yaml └── okh-spikeling.yml /1-click_BOM.tsv: -------------------------------------------------------------------------------- 1 | References,Qty,Description,Manufacturer,MPN,Manufacturer,MPN,Manufacturer,MPN,Manufacturer,MPN,Manufacturer,MPN,Manufacturer,MPN,Digikey,Mouser,RS,Newark,Farnell 2 | MCU,1,Arduino Nano,Arduino,A000087,Arduino,A000005,Gravitech,A000005,,,,,,,1050-1001-ND,782A000005,6961667,,1848691 3 | U5,2,Headers 15 pin 1 row,Samtec inc,SSA-115-S-T,Samtec Inc,SSW-115-01-T-S,Samtec,BCS-115-L-S-TE,Samtec,SSA-115-S-T,Samtec,SSW-115-01-T-S,,,SAM1213-15-ND,200BCS115LSTE,1800452,,2779587 4 | Battery clip,1,9V PP3,KEYSTONE,1294,Keystone,1294,,,,,,,,,36-1294-ND,5341294,1725845,,1650674 5 | Potentiometers,4,10k/50mw/20%,Alps,RK09K1130AH1,ALPS,RK09K1130AH1,,,,,,,,,,,7293587,,1191725 6 | Buzzer,1,25V 75dB,Murata,PKM22EPPH4001-B0,,,,,,,,,,,490-4692-ND,81PKM22EPPH4001B0,5168252,,1192512 7 | BNC connectors,5,female PCB conn,Radiall,R141426161,TE Connectivity,1-1337445-0,,,,,,,,,A101972-ND,571113374450,3941055P,,1205964 8 | Pushbutton,1,35V 10mA,E-switch,KS-01Q-01,C&K,D6C90 F1 LFS,C&K Components,D6C90F1LFS,E-Switch,KS-01Q-01,,,,,401-1969-ND,611D6C90F1LFS,102327,,1201367 9 | LED,2,617nm 2V 20mA,Knightbright,L-793ID,Kingbright,L-793ID,,,,,,,,,,,2471791,,1142588 10 | C1,1,100V 1nf 5%,Multicomp,MCRR50102COGJ0100,Murata,RDE5C1H102J0M1H03A,,,,,,,,,490-8962-1-ND,81RDE5C1H102J0M1H3A,1335665P,,2990765 11 | "R1,R4",2,250V 10k 250mW 1%,Multicomp,MF25 10K,TE connectivity,CFR16J10K,TE Connectivity,CFR16J10K,,,,,,,A104668CT-ND,279CFR16J10K,1251153,,9341110 12 | R2,1,250V 47ohm 250mW 1%,Multicomp,MF25 47R,Ohmite,OD470JE,RS Pro,7077568,,,,,,,OD470JE-ND,588OD470JE,7077568,,9341986 13 | R3,1,250V 10ohm 250mW 1%,Multicomp,MF25 10R,TE connectivity,YR1B10RCC,TE Connectivity,YR1B10RCC,,,,,,,A105944CT-ND,279YR1B10RCC,1372768,,1785905 14 | Battery,1,9V PP3,Panasonic,6F22REL/1BP,Energizer,7638900410297,Energizer,EN22,,,,,,,N145-ND,,9145051,,1018880 15 | BNC cable,1,Male to Male,Amphenol,779829-58-0.6,Cal test,CT2942-50,RS Pro,1222147,Cal Test Electronics,CT2942-50,,,,,BKCT2942-50-ND,510CT294250,1222147,23M9404,1261916 16 | BNC connector,1,Male to wire,Clever little box,CLB-JL-73,Clever Little Box,CLB-JL-732,Clever Little Box,CLB-JL73,,,,,,,,,1242521,,2381877 17 | BNC adapter,1,Jack Jack adaptor,Multicomp,BNC JACK JACK ADAPTOR NICKEL,Amphenol RF,031-219-RFX,Telegärtner,J01004A0618,,,,,,,ARFX1069-ND,52331219RFX,1121798,,1169741 18 | Photodiode,1,IR 20°,Osram Opto,Q62702P0942,Osram,SFH 203 P,Osram Opto,,Osram Opto,,,,,,475-2649-ND,720SFH203FA,6548154,94AC4969,2981688 19 | M3 screws,1,6mm M3,TR Fastenings,M36 KHHTMCS100-,RS-Pro,528-946,Keystone,29311,RS Pro,528946,TR Fastenings,M3 6 KH10MC S100,TR Fastenings,M36KHHTMCS100-,36-29311-ND,53429311,528946,,1420609 20 | M3 nuts,1,M3,TR Fastenings,M3- HFA2-S100-,RS-Pro,560-293,RS Pro,560293,,,,,,,,,560293,53M8680,1420788 21 | -------------------------------------------------------------------------------- /3D print/Spikeling LED holder.3mf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/3D print/Spikeling LED holder.3mf -------------------------------------------------------------------------------- /3D print/Spikeling LED holder.scad: -------------------------------------------------------------------------------- 1 | tol = 0.1; 2 | Smoothness = 200; 3 | Wall = 2; 4 | 5 | r_LED = 8.9/2; 6 | r_led = 8.0/2; 7 | h_LED = 11.2; 8 | h_LED_base = 2.1; 9 | h_LED_top = 3; 10 | 11 | r_photo_base = 6/2; 12 | r_photo = 5/2; 13 | h_photo = 8.9; 14 | h_photo_base = 1; 15 | 16 | 17 | 18 | difference(){ 19 | cylinder (r=r_LED+Wall, h=h_photo, $fn=Smoothness); 20 | 21 | #cylinder (r=r_photo_base+tol, h=h_photo_base+tol, $fn=Smoothness); 22 | translate([0,0,h_photo_base+tol])cylinder(r=r_photo+tol, h=h_photo-h_photo_base+tol, $fn=Smoothness); 23 | } 24 | difference(){ 25 | translate([0,0,h_photo])cylinder(r=r_LED+Wall, h=h_LED, $fn=Smoothness); 26 | 27 | translate([0,0,h_photo+h_LED_top])cylinder(r=r_led+tol, h=h_LED-h_LED_top 28 | , $fn=Smoothness); 29 | translate([0,0,h_photo+h_LED-h_LED_base])cylinder(r=r_LED+tol, h=h_LED_base, $fn=Smoothness); 30 | translate([0,0,h_photo+r_led])sphere(r=r_LED+tol, $fn=Smoothness); 31 | translate([0,0,h_photo])cylinder (r=r_photo+tol, h=h_LED, $fn=Smoothness); 32 | } -------------------------------------------------------------------------------- /Arduino/Spikeling/Definitions.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Global definitions 3 | // ----------------------------------------------------------------------------- 4 | #ifndef Definitions_h 5 | #define Definitions_h 6 | 7 | #define ID_V 0 8 | #define ID_I_TOTAL 1 9 | #define ID_I_PD 2 10 | #define ID_I_ANALOG_IN 3 11 | #define ID_I_SYNAPSE 4 12 | #define ID_I_STIM_STATE 5 13 | #define ID_I_SPIKE_IN1_STATE 6 14 | #define ID_I_SPIKE_IN2_STATE 7 15 | #define ID_I_CURR_MICROSS 8 16 | 17 | // Model output structure 18 | // 19 | typedef struct { 20 | float v, I_total, I_PD, I_AnalogIn, I_Synapse; 21 | int Stim_State, SpikeIn1State, SpikeIn2State; 22 | unsigned long currentMicros; 23 | int NeuronBehaviour; 24 | } output_t; 25 | 26 | #endif 27 | // ----------------------------------------------------------------------------- 28 | -------------------------------------------------------------------------------- /Arduino/Spikeling/Mcp23s18/Mcp23s08.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if defined(ESP32) || defined(ESP8622) 8 | #else 9 | #include 10 | #endif 11 | 12 | #include "Mcp23s08.h" 13 | 14 | // ----------------------------------------------------------------------------- 15 | MCP23S08::MCP23S08(){ 16 | #if defined (SPI_HAS_TRANSACTION) 17 | _spiTransactionsSpeed = MAXSPISPEED;//set to max supported speed (in relation to chip and CPU) 18 | #else 19 | _spiTransactionsSpeed = 0; 20 | #endif 21 | } 22 | 23 | void MCP23S08::setSPIspeed(uint32_t spispeed){ 24 | #if defined (SPI_HAS_TRANSACTION) 25 | if (spispeed > 0){ 26 | if (spispeed > MAXSPISPEED) { 27 | _spiTransactionsSpeed = MAXSPISPEED; 28 | } else { 29 | _spiTransactionsSpeed = spispeed; 30 | } 31 | } else { 32 | _spiTransactionsSpeed = 0;//disable SPItransactons 33 | } 34 | #else 35 | _spiTransactionsSpeed = 0; 36 | #endif 37 | } 38 | 39 | //return 255 if the choosed pin has no INT, otherwise return INT number 40 | //if there's support for SPI transactions it will use SPI.usingInterrupt(intNum); 41 | //to prevent problems from interrupt 42 | /*USE: 43 | int intNumber = mcp.getInterruptNumber(gpio_int_pin); 44 | if (intNumber < 255){ 45 | attachInterrupt(intNumber, keypress, FALLING);//attack interrupt 46 | } else { 47 | Serial.println("sorry, pin has no INT capabilities!"); 48 | } 49 | */ 50 | 51 | // ***TE 2018-08-18*** 52 | // Disabled because SPI.usingInterrupt() not defined for ESPxxx 53 | /* 54 | int mcp23s08::getInterruptNumber(byte pin) { 55 | int intNum = digitalPinToInterrupt(pin); 56 | if (intNum != NOT_AN_INTERRUPT) { 57 | #if defined (SPI_HAS_TRANSACTION) 58 | SPI.usingInterrupt(intNum); 59 | #endif 60 | return intNum; 61 | } 62 | return 255; 63 | } 64 | */ 65 | MCP23S08::MCP23S08(const uint8_t csPin,const uint8_t haenAdrs){ 66 | _spiTransactionsSpeed = 0; 67 | mSpi = &SPI; 68 | postSetup(csPin,haenAdrs,&SPI); 69 | } 70 | 71 | MCP23S08::MCP23S08(const uint8_t csPin,const uint8_t haenAdrs,uint32_t spispeed){ 72 | postSetup(csPin,haenAdrs,&SPI,spispeed); 73 | } 74 | 75 | MCP23S08::MCP23S08(const uint8_t csPin,const uint8_t haenAdrs,uint32_t spispeed,SPIClass *spi){ 76 | postSetup(csPin,haenAdrs,spi,spispeed); 77 | } 78 | 79 | 80 | void MCP23S08::postSetup(const uint8_t csPin,const uint8_t haenAdrs,SPIClass *spi,uint32_t spispeed){ 81 | #if defined (SPI_HAS_TRANSACTION) 82 | if (spispeed > 0) setSPIspeed(spispeed); 83 | #endif 84 | mSpi = spi; 85 | _cs = csPin; 86 | if (haenAdrs >= 0x20 && haenAdrs <= 0x23){//HAEN works between 0x20...0x23 87 | _adrs = haenAdrs; 88 | _useHaen = 1; 89 | } else { 90 | _adrs = 0; 91 | _useHaen = 0; 92 | } 93 | _readCmd = (_adrs << 1) | 1; 94 | _writeCmd = _adrs << 1; 95 | //setup register values for this chip 96 | IOCON = 0x05; 97 | IODIR = 0x00; 98 | GPPU = 0x06; 99 | GPIO = 0x09; 100 | GPINTEN = 0x02; 101 | IPOL = 0x01; 102 | DEFVAL = 0x03; 103 | INTF = 0x07; 104 | INTCAP = 0x08; 105 | OLAT = 0x0A; 106 | INTCON = 0x04; 107 | } 108 | 109 | void MCP23S08::begin(bool protocolInitOverride) { 110 | if (protocolInitOverride){ 111 | mSpi->begin(); 112 | #if defined (SPI_HAS_TRANSACTION) 113 | if (_spiTransactionsSpeed == 0){//do not use SPItransactons 114 | mSpi->setClockDivider(SPI_CLOCK_DIV4); // 4 MHz (half speed) 115 | mSpi->setBitOrder(MSBFIRST); 116 | mSpi->setDataMode(SPI_MODE0); 117 | } 118 | #else//do not use SPItransactons 119 | mSpi->setClockDivider(SPI_CLOCK_DIV4); // 4 MHz (half speed) 120 | mSpi->setBitOrder(MSBFIRST); 121 | mSpi->setDataMode(SPI_MODE0); 122 | #endif 123 | } 124 | pinMode(_cs, OUTPUT); 125 | digitalWrite(_cs, HIGH); 126 | delay(100); 127 | 128 | _useHaen == 1 ? writeByte(IOCON,0b00101000) : writeByte(IOCON,0b00100000); 129 | /* 130 | if (_useHaen){ 131 | writeByte(IOCON,0b00101000);//read datasheet for details! 132 | } else { 133 | writeByte(IOCON,0b00100000); 134 | } 135 | */ 136 | _gpioDirection = 0xFF;//all in 137 | _gpioState = 0x00;//all low 138 | } 139 | 140 | 141 | uint8_t MCP23S08::readAddress(byte addr){ 142 | byte low_byte = 0x00; 143 | startSend(1); 144 | mSpi->transfer(addr); 145 | low_byte = mSpi->transfer(0x0); 146 | endSend(); 147 | return low_byte; 148 | } 149 | 150 | 151 | void MCP23S08::gpioPinMode(uint8_t mode){ 152 | if (mode == INPUT){ 153 | _gpioDirection = 0xFF; 154 | } else if (mode == OUTPUT){ 155 | _gpioDirection = 0x00; 156 | _gpioState = 0x00; 157 | } else { 158 | _gpioDirection = mode; 159 | } 160 | writeByte(IODIR,_gpioDirection); 161 | } 162 | 163 | 164 | void MCP23S08::gpioPinMode(uint8_t pin, uint8_t mode){ 165 | if (pin < 8){//0...7 166 | mode == INPUT ? _gpioDirection |= (1 << pin) :_gpioDirection &= ~(1 << pin); 167 | writeByte(IODIR,_gpioDirection); 168 | } 169 | } 170 | 171 | 172 | void MCP23S08::gpioPort(uint8_t value){ 173 | if (value == HIGH){ 174 | _gpioState = 0xFF; 175 | } else if (value == LOW){ 176 | _gpioState = 0x00; 177 | } else { 178 | _gpioState = value; 179 | } 180 | writeByte(GPIO,_gpioState); 181 | } 182 | 183 | 184 | uint8_t MCP23S08::readGpioPort(){ 185 | return readAddress(GPIO); 186 | } 187 | 188 | uint8_t MCP23S08::readGpioPortFast(){ 189 | return _gpioState; 190 | } 191 | 192 | int MCP23S08::gpioDigitalReadFast(uint8_t pin){ 193 | if (pin < 8){//0...7 194 | int temp = bitRead(_gpioState,pin); 195 | return temp; 196 | } else { 197 | return 0; 198 | } 199 | } 200 | 201 | void MCP23S08::portPullup(uint8_t data) { 202 | if (data == HIGH){ 203 | _gpioState = 0xFF; 204 | } else if (data == LOW){ 205 | _gpioState = 0x00; 206 | } else { 207 | _gpioState = data; 208 | } 209 | writeByte(GPPU, _gpioState); 210 | } 211 | 212 | 213 | 214 | 215 | void MCP23S08::gpioDigitalWrite(uint8_t pin, bool value){ 216 | if (pin < 8){//0...7 217 | value == HIGH ? _gpioState |= (1 << pin) : _gpioState &= ~(1 << pin); 218 | writeByte(GPIO,_gpioState); 219 | } 220 | } 221 | 222 | void MCP23S08::gpioDigitalWriteFast(uint8_t pin, bool value){ 223 | if (pin < 8){//0...8 224 | value == HIGH ? _gpioState |= (1 << pin) : _gpioState &= ~(1 << pin); 225 | } 226 | } 227 | 228 | void MCP23S08::gpioPortUpdate(){ 229 | writeByte(GPIO,_gpioState); 230 | } 231 | 232 | int MCP23S08::gpioDigitalRead(uint8_t pin){ 233 | if (pin < 8) return (int)(readAddress(GPIO) & 1 << pin); 234 | return 0; 235 | } 236 | 237 | uint8_t MCP23S08::gpioRegisterReadByte(byte reg){ 238 | uint8_t data = 0; 239 | startSend(1); 240 | mSpi->transfer(reg); 241 | data = mSpi->transfer(0); 242 | endSend(); 243 | return data; 244 | } 245 | 246 | 247 | void MCP23S08::gpioRegisterWriteByte(byte reg,byte data){ 248 | writeByte(reg,(byte)data); 249 | } 250 | 251 | /* ------------------------------ Low Level ----------------*/ 252 | void MCP23S08::startSend(bool mode){ 253 | #if defined (SPI_HAS_TRANSACTION) 254 | if (_spiTransactionsSpeed > 0) 255 | mSpi->beginTransaction(SPISettings(_spiTransactionsSpeed, MSBFIRST, SPI_MODE0)); 256 | #endif 257 | #if defined(__FASTWRITE) 258 | digitalWriteFast(_cs, LOW); 259 | #else 260 | digitalWrite(_cs, LOW); 261 | #endif 262 | mode == 1 ? mSpi->transfer(_readCmd) : mSpi->transfer(_writeCmd); 263 | } 264 | 265 | void MCP23S08::endSend(){ 266 | #if defined(__FASTWRITE) 267 | digitalWriteFast(_cs, HIGH); 268 | #else 269 | digitalWrite(_cs, HIGH); 270 | #endif 271 | #if defined (SPI_HAS_TRANSACTION) 272 | if (_spiTransactionsSpeed > 0) 273 | mSpi->endTransaction(); 274 | #endif 275 | } 276 | 277 | 278 | void MCP23S08::writeByte(byte addr, byte data){ 279 | startSend(0); 280 | mSpi->transfer(addr); 281 | mSpi->transfer(data); 282 | endSend(); 283 | } 284 | 285 | // ----------------------------------------------------------------------------- 286 | -------------------------------------------------------------------------------- /Arduino/Spikeling/Mcp23s18/Mcp23s08.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Adapted from https://github.com/sumotoy/gpio_expander 3 | // by Thomas Euler (2018-08-18) 4 | // 5 | // ----------------------------------------------------------------------------- 6 | /* 7 | ___ _ _ _ __ ___ ___ | |_ ___ _ _ 8 | / __|| | | || '_ ` _ \ / _ \ | __|/ _ \ | | | | 9 | \__ \| |_| || | | | | || (_) || |_| (_) || |_| | 10 | |___/ \__,_||_| |_| |_| \___/ \__|\___/ \__, | 11 | |___/ 12 | 13 | gpio_expander - An attemp to create a fast and universal library for drive many GPIO chips 14 | 15 | model: company: pins: protocol: Special Features: 16 | --------------------------------------------------------------------------------------------------------------------- 17 | mcp23s08 Microchip 8 SPI INT/HAEN 18 | --------------------------------------------------------------------------------------------------------------------- 19 | Version history: 20 | 0.5b1: first release, just coded and never tested 21 | 0.5b2: fixed 2wire version, added portPullup, tested output mode (ok) 22 | 0.5b3: added some drivers 23 | 0.5b4: ability to include library inside other libraries. 24 | 0.5b7: Changed functionalities of some function. 25 | 0.6b1: Changed gpioRegisterRead to gpioRegisterReadByte. Added gpioRegisterReadWord (for some GPIO) 26 | 0.6b3: Added basic support for SPI transactions, small optimizations. 27 | 0.8b3: Added 2 more commands and 2 gpio chip. 28 | 0.8b4: Support for SPI Transaction post setup 29 | --------------------------------------------------------------------------------------------------------------------- 30 | Copyright (c) 2013-2014, s.u.m.o.t.o.y [sumotoy(at)gmail.com] 31 | --------------------------------------------------------------------------------------------------------------------- 32 | 33 | gpio_expander Library is free software: you can redistribute it and/or modify 34 | it under the terms of the GNU General Public License as published by 35 | the Free Software Foundation, either version 3 of the License, or 36 | (at your option) any later version. 37 | 38 | gpio_expander Library is distributed in the hope that it will be useful, 39 | but WITHOUT ANY WARRANTY; without even the implied warranty of 40 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41 | GNU General Public License for more details. 42 | 43 | You should have received a copy of the GNU General Public License 44 | along with Foobar. If not, see . 45 | 46 | 47 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 48 | Version:0.8b3: Added 2 more commands and 2 gpio chip. 49 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 50 | */ 51 | 52 | /* ------------------------------ MCP23S08 WIRING ------------------------------------ 53 | This chip has a very useful feature called HAEN that allow you to share the same CS pin trough 54 | 4 different addresses. Of course chip has to be Microchip and should be assigned to different addresses! 55 | 56 | Basic Address: 001000 A1 A0 (from 0x20 to 0x23) 57 | A1,A0 tied to ground = 0x20 58 | __ __ 59 | -> sck [| U |] ++++ 60 | -> mosi [| |] IO-7 61 | <- miso [| |] IO-6 62 | A1 [| |] IO-5 63 | A0 [| |] IO-4 64 | rst (con.+) [| |] IO-3 65 | cs [| |] IO-2 66 | int [| |] IO-1 67 | GND [|_____|] IO-0 68 | */ 69 | // ----------------------------------------------------------------------------- 70 | 71 | #ifndef _MCP23S08_H_ 72 | #define _MCP23S08_H_ 73 | 74 | #include 75 | #include 76 | #include "gpio_expander.h" 77 | #include "SPI.parameters.h" 78 | 79 | // ----------------------------------------------------------------------------- 80 | 81 | class MCP23S08 : public gpio_expander 82 | { 83 | 84 | public: 85 | MCP23S08(const uint8_t csPin,const uint8_t haenAdrs); 86 | MCP23S08(const uint8_t csPin,const uint8_t haenAdrs,uint32_t spispeed); 87 | MCP23S08(const uint8_t csPin,const uint8_t haenAdrs,uint32_t spispeed, SPIClass *spi); 88 | 89 | MCP23S08(); 90 | void postSetup(const uint8_t csPin,const uint8_t haenAdrs,SPIClass *spi,uint32_t spispeed=0); //used with other libraries only 91 | virtual void begin(bool protocolInitOverride=false); //protocolInitOverride=false will not init the SPI 92 | 93 | 94 | void gpioPinMode(uint8_t mode); //set all pins to INPUT or OUTPUT 95 | void gpioPinMode(uint8_t pin, uint8_t mode); //set a unique pin as INPUT or OUTPUT 96 | void gpioPort(uint8_t value); //write data to all pins 97 | //void gpioPort(byte lowByte, byte highByte); //same as abowe but uses 2 separate bytes (not applicable to this chip) 98 | uint8_t readGpioPort(); //read the state of the pins (all) 99 | uint8_t readGpioPortFast(); 100 | 101 | void gpioDigitalWrite(uint8_t pin, bool value); //write data to one pin 102 | void gpioDigitalWriteFast(uint8_t pin, bool value); 103 | int gpioDigitalRead(uint8_t pin); //read data from one pin 104 | uint8_t gpioRegisterReadByte(byte reg); //read a byte from chip register 105 | int gpioDigitalReadFast(uint8_t pin); 106 | void gpioRegisterWriteByte(byte reg,byte data); //write a chip register 107 | void portPullup(uint8_t data); // true=pullup, false=pulldown all pins 108 | void gpioPortUpdate(); 109 | // direct access commands 110 | uint8_t readAddress(byte addr); 111 | //int getInterruptNumber(byte pin); 112 | void setSPIspeed(uint32_t spispeed);//for SPI transactions 113 | 114 | //------------------------- REGISTERS 115 | byte IOCON; 116 | byte IODIR; 117 | byte GPPU; 118 | byte GPIO; 119 | byte GPINTEN; 120 | byte IPOL; 121 | byte DEFVAL; 122 | byte INTF; 123 | byte INTCAP; 124 | byte OLAT; 125 | byte INTCON; 126 | 127 | private: 128 | uint8_t _cs; 129 | uint8_t _adrs; 130 | 131 | uint32_t _spiTransactionsSpeed;//for SPI transactions 132 | SPIClass *mSpi; 133 | 134 | uint8_t _useHaen; 135 | uint8_t _readCmd; 136 | uint8_t _writeCmd; 137 | void startSend(bool mode); 138 | void endSend(); 139 | uint8_t _gpioDirection; 140 | uint8_t _gpioState; 141 | void writeByte(byte addr, byte data); 142 | }; 143 | #endif -------------------------------------------------------------------------------- /Arduino/Spikeling/Mcp23s18/SPI.parameters.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | #ifndef _GPIO_SPI_PARAM_H_ 3 | #define _GPIO_SPI_PARAM_H_ 4 | 5 | //defining max SPI speed (not definitive and can change in relation to chip used) 6 | #if defined (SPI_HAS_TRANSACTION) 7 | #if defined(__MK20DX128__) || defined(__MK20DX256__)//Teensy 3.0 or 3.1 8 | #define MAXSPISPEED 30000000 9 | #elif defined(__MKL26Z64__) //Teensy LC 10 | #define MAXSPISPEED 12000000 11 | #elif defined(ARDUINO) && defined(__arm__) && !defined(CORE_TEENSY) //DUE 12 | #define MAXSPISPEED 24000000 13 | #elif defined(__32MX320F128H__) || defined(__32MX795F512L__) //uno and max chipkit 14 | #define MAXSPISPEED 8000000 15 | #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 16 | #define MAXSPISPEED 2000000 17 | #elif defined (__AVR_ATmega328P__) || defined (__AVR_ATmega168P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644PA__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) 18 | #define MAXSPISPEED 8000000 19 | #else 20 | #define MAXSPISPEED 2000000 21 | #endif 22 | #endif 23 | 24 | #endif 25 | // ----------------------------------------------------------------------------- 26 | -------------------------------------------------------------------------------- /Arduino/Spikeling/Mcp23s18/gpio_expander.cpp: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if defined(ESP32) || defined(ESP8622) 8 | #else 9 | #include 10 | #endif 11 | 12 | #include "gpio_expander.h" 13 | 14 | gpio_expander::gpio_expander() 15 | { 16 | } 17 | 18 | // ----------------------------------------------------------------------------- 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Arduino/Spikeling/Mcp23s18/gpio_expander.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Adapted from https://github.com/sumotoy/gpio_expander 3 | // by Thomas Euler (2018-08-18) 4 | // 5 | // ----------------------------------------------------------------------------- 6 | /* 7 | gpio_expander - An attemp to create a fast and universal library for drive many GPIO chips 8 | 9 | Features: 10 | 11 | - Can drive many type of GPIO's chip from different makers. 12 | - Use almost same commands for all chips so they can be easily exchanged. 13 | - Can access special registers of some chip. 14 | 15 | Copyright (c) 2013-2014, sumotoy, coded by Max MC Costa. 16 | 17 | gpio_expander Library is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU General Public License as published by 19 | the Free Software Foundation, either version 3 of the License, or 20 | (at your option) any later version. 21 | 22 | gpio_expander Library is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU General Public License for more details. 26 | 27 | You should have received a copy of the GNU General Public License 28 | along with Foobar. If not, see . 29 | 30 | 31 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 32 | Version:0.8b3 - Fixed an error that blocks I/O 16 in many functions 33 | (thanks Thorsten to point me this) 34 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 35 | */ 36 | // ----------------------------------------------------------------------------- 37 | #ifndef _GPIO_EXPANDER_H_ 38 | #define _GPIO_EXPANDER_H_ 39 | 40 | #include 41 | #include 42 | 43 | #if defined(ESP32) || defined(ESP8622) 44 | #else 45 | #include 46 | #endif 47 | #if defined(__MK20DX128__) || defined(__MK20DX256__) //Teensy 3.0 or 3.1 48 | #define __FASTWRITE 49 | #endif 50 | 51 | // ----------------------------------------------------------------------------- 52 | class gpio_expander { 53 | 54 | public: 55 | gpio_expander( ); 56 | 57 | virtual void begin(bool protocolInitOverride=false) = 0; 58 | 59 | //void command(); 60 | 61 | 62 | protected: 63 | inline uint16_t byte2word(byte high_byte,byte low_byte){return (word)high_byte << 8 | (word)low_byte;}; 64 | inline byte word2highByte(uint16_t data){return (byte)(data >> 8);}; 65 | inline byte word2lowByte(uint16_t data){return (byte)(data & 0x00FF);}; 66 | 67 | private: 68 | 69 | }; 70 | #endif 71 | // ----------------------------------------------------------------------------- -------------------------------------------------------------------------------- /Arduino/Spikeling/Mcp23s18/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For gpio_expander 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | mcp23s17 KEYWORD1 10 | mcp23017 KEYWORD1 11 | mcp23s08 KEYWORD1 12 | mcp23008 KEYWORD1 13 | mcp23s18 KEYWORD1 14 | mcp23018 KEYWORD1 15 | mcp23016 KEYWORD1 16 | pcf8574 KEYWORD1 17 | pcf8574a KEYWORD1 18 | pcf8575 KEYWORD1 19 | pca9555 KEYWORD1 20 | pca9655 KEYWORD1 21 | max7318 KEYWORD1 22 | max7311 KEYWORD1 23 | max6957 KEYWORD1 24 | max7301 KEYWORD1 25 | 26 | ####################################### 27 | # Methods and Functions (KEYWORD2) 28 | ####################################### 29 | 30 | begin KEYWORD2 31 | writeByte KEYWORD2 32 | writeWord KEYWORD2 33 | readAddress KEYWORD2 34 | gpioPinMode KEYWORD2 35 | gpioPort KEYWORD2 36 | readGpioPort KEYWORD2 37 | readGpioPortFast KEYWORD2 38 | gpioDigitalWrite KEYWORD2 39 | gpioDigitalWriteFast KEYWORD2 40 | gpioDigitalRead KEYWORD2 41 | gpioRegisterReadByte KEYWORD2 42 | gpioRegisterReadWord KEYWORD2 43 | gpioDigitalReadFast KEYWORD2 44 | gpioRegisterWriteByte KEYWORD2 45 | gpioRegisterWriteWord KEYWORD2 46 | portPullup KEYWORD2 47 | gpioPortUpdate KEYWORD2 48 | getInterruptNumber KEYWORD2 49 | 50 | ####################################### 51 | # Constants (LITERAL1) 52 | ####################################### 53 | 54 | IOCON LITERAL1 55 | IODIR LITERAL1 56 | GPPU LITERAL1 57 | GPIO LITERAL1 58 | GPINTEN LITERAL1 59 | IPOL LITERAL1 60 | DEFVAL LITERAL1 61 | INTF LITERAL1 62 | INTCAP LITERAL1 63 | OLAT LITERAL1 64 | INTCON LITERAL1 65 | 66 | 67 | -------------------------------------------------------------------------------- /Arduino/Spikeling/README.md: -------------------------------------------------------------------------------- 1 | When using ESP boards, move the folder `Mcp23s18` to the directory where the Arduino GUI looks for libraries (usually `\Arduino\libraries\`). 2 | 3 | 4 | -------------------------------------------------------------------------------- /Arduino/Spikeling/SettingsArduino.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Settings for the Arduino Pro (Mini) 3 | // 4 | // ----------------------------------------------------------------------------- 5 | //#define USES_FAST_ADC 6 | // Change ADC prescaler 16, which slighly decreases the ADC precision but 7 | // speeds up the time per loop by ~20% 8 | 9 | #define USES_HOUSEKEEPING 10 | // Reads all ADCs in one pass 11 | 12 | //#define USES_FASTER_PWM 13 | // Sets PWM pins 3 and 11 (timer 2) to 31250 Hz 14 | 15 | //#define USES_PLOTTING 16 | //#define USES_FULL_REDRAW 17 | //#define USES_DAC 18 | 19 | #include "Definitions.h" 20 | 21 | // ----------------------------------------------------------------------------- 22 | // Pin definitions (simulation-related) 23 | // ----------------------------------------------------------------------------- 24 | #define PhotoDiodePin A0 // Photodiode 25 | #define LEDOutPin 9 // LED 26 | #define ButtonPin 2 // Push button to switch spike modes 27 | #define VmPotPin A3 // Resting membrane potential 28 | #define Syn1PotPin A7 // efficacy synapse 1 29 | #define Syn2PotPin A5 // efficacy synapse 2 30 | #define NoisePotPin A6 // scaling of Noise level 31 | #define DigitalIn1Pin 4 // Synapse 1 Input - expects 5V pulses 32 | #define DigitalIn2Pin 5 // Synapse 2 input - expects 5V pulses 33 | #define AnalogInPin A2 // Analog in- takes 0-5V (positive only) 34 | #define DigitalOutPin 3 // "Axon" - generates 5V pulses 35 | #define AnalogOutPin 11 // Analog out for full spike waveform 36 | 37 | #ifdef USES_HOUSEKEEPING 38 | #define MAX_ADC_DATA 8 39 | #define N_ADC_IND 6 40 | uint16_t ADCData[MAX_ADC_DATA]; 41 | uint8_t iADCData[] = {PhotoDiodePin, VmPotPin, Syn1PotPin, Syn2PotPin, 42 | NoisePotPin, AnalogInPin}; 43 | #endif 44 | 45 | // Digital and analog I/O helper macros 46 | // 47 | #define pinModeHelper(pin, mode) pinMode(pin, mode) 48 | #define digitalReadHelper(pin) digitalRead(pin) 49 | #define digitalWriteHelper(pin, val) digitalWrite(pin, val) 50 | #define analogWriteHelper(pin, val) analogWrite(pin, val) 51 | #ifdef USES_HOUSEKEEPING 52 | #define analogReadHelper(pin) ADCData[pin -A0] 53 | #else 54 | #define analogReadHelper(pin) analogRead(pin) 55 | #endif 56 | 57 | // Serial out 58 | // 59 | #define SerOutBAUD 234000 60 | 61 | // ----------------------------------------------------------------------------- 62 | // Pin definitions (hardware add-ons) 63 | // ----------------------------------------------------------------------------- 64 | 65 | // ----------------------------------------------------------------------------- 66 | // Other hardware-related definitions 67 | // ----------------------------------------------------------------------------- 68 | // Setting and clearing register bits 69 | // 70 | #ifdef USES_FAST_ADC 71 | #ifndef cbi 72 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 73 | #endif 74 | #ifndef sbi 75 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 76 | #endif 77 | #ifndef cli 78 | #define disable_interrupts cli() 79 | #endif 80 | #ifndef sei 81 | #define enable_interrupts sei() 82 | #endif 83 | #endif 84 | 85 | // ----------------------------------------------------------------------------- 86 | void ADC_init(void) 87 | { 88 | // Initialise buffers 89 | // 90 | for(uint8_t i=0; i 31 | #include "MiniGrafx.h" 32 | #include "ILI9341_SPI.h" 33 | #include 34 | #include 35 | #include 36 | 37 | // ----------------------------------------------------------------------------- 38 | #define MCP3208_FIRST 100 39 | #define MCP3208_LAST 107 40 | #define MCP23S08_FIRST 110 41 | #define MCP23S08_LAST 117 42 | 43 | // ----------------------------------------------------------------------------- 44 | // Pin definitions (simulation-related) 45 | // ----------------------------------------------------------------------------- 46 | #ifdef ESP8266 47 | #define PhotoDiodePin -1 // Photodiode 48 | #define LEDOutPin -2 // LED 49 | #define ButtonPin -3 // Push button to switch spike modes 50 | #define VmPotPin -4 // Resting membrane potential 51 | #define Syn1PotPin -5 // efficacy synapse 1 52 | #define Syn2PotPin -6 // efficacy synapse 2 53 | #define NoisePotPin -7 // scaling of Noise level 54 | #define DigitalIn1Pin -8 // Synapse 1 Input - expects 5V pulses 55 | #define DigitalIn2Pin -9 // Synapse 2 input - expects 5V pulses 56 | #define AnalogInPin -10 // Analog in- takes 0-5V (positive only) 57 | #define DigitalOutPin -11 // "Axon" - generates 5V pulses 58 | #define AnalogOutPin -12 // Analog out for full spike waveform 59 | #define DACOutPin -13 // NEW Analog out for full spike waveform (analog) 60 | #define HousekeepLED -14 // NEW 61 | 62 | // Digital and analog I/O helper macros 63 | // 64 | #define pinModeHelper(pin, mode) pinModeNew(pin, mode) 65 | #define digitalReadHelper(pin) digitalReadNew(pin) 66 | #define digitalWriteHelper(pin, val) digitalWriteNew(pin, val) 67 | #define analogReadHelper(pin) analogReadNew(pin) 68 | #define analogWriteHelper(pin, val) analogWriteNew(pin, val) 69 | #define dacWriteHelper(pin, val) dummy(pin, val) 70 | #endif 71 | #ifdef ESP32 72 | #define PhotoDiodePin MCP3208_FIRST+2 // -> A0 Photodiode 73 | #define LEDOutPin 21 // -> D9/PWM LED 74 | #define ButtonPin MCP23S08_FIRST+1 // -> 2 Push button to switch spike modes 75 | #define VmPotPin MCP3208_FIRST+0 // -> A3 Resting membrane potential 76 | #define Syn1PotPin MCP3208_FIRST+3 // -> A7 efficacy synapse 1 77 | #define Syn2PotPin MCP3208_FIRST+4 // -> A5 efficacy synapse 2 78 | #define NoisePotPin MCP3208_FIRST+1 // -> A6 scaling of Noise level 79 | #define DigitalIn1Pin MCP23S08_FIRST+2 // -> 4 Synapse 1 Input - expects 5V pulses 80 | #define DigitalIn2Pin MCP23S08_FIRST+3 // -> 5 Synapse 2 input - expects 5V pulses 81 | #define AnalogInPin MCP3208_FIRST+5 // -> A2 Analog in- takes 0-5V (positive only) 82 | #define DigitalOutPin 16 // -> D3/DO "Axon" - generates 5V pulses 83 | #define AnalogOutPin 17 // -> D11/PWM Analog out for full spike waveform 84 | #define DACOutPin A0 // NEW Analog out for full spike waveform (analog) 85 | #define HousekeepLED MCP23S08_FIRST+0 // NEW 86 | 87 | // Digital and analog I/O helper macros 88 | // 89 | #define pinModeHelper(pin, mode) pinModeNew(pin, mode) 90 | #define digitalReadHelper(pin) digitalReadNew(pin) 91 | #define digitalWriteHelper(pin, val) digitalWriteNew(pin, val) 92 | #define analogReadHelper(pin) analogReadNew(pin) 93 | #define analogWriteHelper(pin, val) analogWriteNew(pin, val) 94 | #define dacWriteHelper(pin, val) dacWrite(pin, val) 95 | 96 | // NOTES: 97 | // (1) analogWrite() is not implemented in the ESP32, therefore use ledcXXX() 98 | // functions instead. This requires an LED channel ID (0..15), a frequency 99 | // (not sure what unit that is ...) and a bit depth (up to 16 bits) 100 | // https://github.com/espressif/arduino-esp32/blob/a4305284d085caeddd1190d141710fb6f1c6cbe1/cores/esp32/esp32-hal-ledc.c 101 | // 102 | #define LEDOut_LEDCh 0 103 | #define LEDOut_Freq 31250 104 | #define LEDOut_Bits 8 105 | #define AnalogOut_LEDCh 1 106 | #define AnalogOut_Freq LEDOut_Freq 107 | #define AnalogOut_Bits LEDOut_Bits 108 | // 109 | // (2) analogReadNew() uses the 8-channel ADC MCP3208; therefore instead of 110 | // pins, the mapping to the ADC channels on the chip are defined above, 111 | // It's a 12 bit ADC, therefore the results need to be divided by 4. 112 | // The MCP3208 is connected to the second SPI bus of the ESP (HSPI), while 113 | // the TFT display uses the primary SPI bus (VSPI). This is nescessary to 114 | // be able to run the TFT at a particular frequency, at which the MCP3208 115 | // does not seem to work reliable. 116 | // For pins, see "hardware add-ons" section further below. 117 | #endif 118 | 119 | // Serial out 120 | // (115200=testing; 921600=standard; 1843200=a bit faster but less stable) 121 | // 122 | #define SerOutBAUD 921600 123 | 124 | // ----------------------------------------------------------------------------- 125 | // Pin definitions (hardware add-ons) 126 | // ----------------------------------------------------------------------------- 127 | #ifdef ESP8266 128 | #define TFT_DC D2 129 | #define TFT_CS D1 130 | #define TFT_LED D8 131 | #define TOUCH_CS D3 132 | #define TOUCH_IRQ D4 133 | ADC_MODE(ADC_VCC); 134 | #endif 135 | #ifdef ESP32 136 | #define TFT_DC 33 137 | #define TFT_CS 15 // primary SPI bus (VSPI), client #1 138 | #define TOUCH_CS 32 // primary SPI bus (VSPI), client #2 139 | #define ADC_MISO 23 // secondary SPI bus (HSPI) ... 140 | #define ADC_MOSI 22 141 | #define ADC_SCK 27 142 | #define ADC_CS 13 // secondary SPI bus (HSPI), client #1 143 | #define DIO_CS 4 // secondary SPI bus (HSPI), client #2 144 | #define DIO_ADDR 0x20 // address of MCP23S08 (defined by A0,A1 pins) 145 | #define DIO_INT 36 // interrupt pin of MCP23S08 (not yet used) 146 | #define ADC_VREF 5000 // Vref for A/D 147 | #define ADC_CLK 1600000 // secondary SPI bus (HSPI), clock 148 | //#define ADC_CLK 4000000 // secondary SPI bus (HSPI), clock 149 | 150 | #endif 151 | 152 | // Define colors usable in the paletted 16 color frame buffer 153 | // 154 | uint16_t palette[] = {ILI9341_BLACK, // 0 155 | ILI9341_WHITE, // 1 156 | ILI9341_NAVY, // 2 157 | ILI9341_DARKCYAN, // 3 158 | ILI9341_DARKGREEN, // 4 159 | ILI9341_MAROON, // 5 160 | ILI9341_PURPLE, // 6 161 | ILI9341_OLIVE, // 7 162 | ILI9341_LIGHTGREY, // 8 163 | ILI9341_DARKGREY, // 9 164 | ILI9341_BLUE, // 10 165 | ILI9341_GREEN, // 11 166 | ILI9341_CYAN, // 12 167 | ILI9341_RED, // 13 168 | ILI9341_MAGENTA, // 14 169 | ILI9341_YELLOW}; // 15 170 | 171 | const int SCREEN_WIDTH = 320; 172 | const int SCREEN_HEIGHT = 240; 173 | const int BITS_PER_PIXEL = 4; // 2^4 = 16 colors 174 | const int FONT_HEIGHT = 14; // Standard font 175 | #ifdef ESP8266 176 | const int SCREEN_ORIENT = 3; 177 | #endif 178 | #ifdef ESP32 179 | const int SCREEN_ORIENT = 1; 180 | #endif 181 | 182 | // Initialize the drivers 183 | // 184 | ILI9341_SPI tft = ILI9341_SPI(TFT_CS, TFT_DC); 185 | MiniGrafx gfx = MiniGrafx(&tft, BITS_PER_PIXEL, palette); 186 | Adafruit_STMPE610 ts = Adafruit_STMPE610(TOUCH_CS); 187 | #ifdef ESP32 188 | SPIClass *hspi = new SPIClass(HSPI); 189 | MCP3208 adc(ADC_VREF, ADC_CS, hspi); 190 | uint16_t ADCData[8][2]; 191 | MCP23S08 dio(DIO_CS, DIO_ADDR, 0, hspi); 192 | uint8_t DIOData; 193 | #endif 194 | 195 | // Definitions and variables for plotting 196 | // 197 | #define INFO_DY 20 // Height of info panel 198 | #define MAX_TRACES 3 // Maximal number of traces shown in parallel 199 | #define MAX_VALUES 320 // Maximal trace length 200 | #define PLOT_UPDATE 16 // Redraw screen every # values 201 | 202 | const char* OutputInfoStr[] = {"V_m[mV]", "I_t[pA]", "I_PD[pA]", "I_AI[pA]", 203 | "I_Sy[pA]", "StmSt", "SpIn1", "SpIn2", 204 | "t[us]"}; 205 | 206 | int TraceCols[MAX_TRACES] = {13,11,15}; 207 | int Traces[MAX_TRACES][MAX_VALUES]; 208 | int TracesStrIndex[MAX_TRACES]; 209 | int TraceSet; 210 | float TracesMinMax[MAX_TRACES][2]; 211 | int iPnt, dyPlot, dxInfo; 212 | char timeStr[16]; 213 | bool stateHousekeepingLED; 214 | 215 | // ----------------------------------------------------------------------------- 216 | // Other hardware-related definitions 217 | // ----------------------------------------------------------------------------- 218 | 219 | // ----------------------------------------------------------------------------- 220 | // Helpers 221 | // ----------------------------------------------------------------------------- 222 | void setTraceSet() 223 | { 224 | switch(TraceSet) { 225 | case 0: 226 | default: 227 | TracesStrIndex[0] = ID_V; 228 | TracesMinMax[0][0] = -110; 229 | TracesMinMax[0][1] = 25; 230 | TracesStrIndex[1] = ID_I_TOTAL; 231 | TracesMinMax[1][0] = -250; 232 | TracesMinMax[1][1] = 250; 233 | TracesStrIndex[2] = ID_I_STIM_STATE; 234 | TracesMinMax[2][0] = -50; 235 | TracesMinMax[2][1] = 50; 236 | } 237 | } 238 | 239 | 240 | void initializeHardware() 241 | { 242 | #ifdef ESP8266 243 | // Turn on the background LED of TFT 244 | // 245 | pinMode(TFT_LED, OUTPUT); 246 | digitalWrite(TFT_LED, HIGH); 247 | 248 | // Set pins 249 | // 250 | // ... 251 | #endif 252 | #ifdef ESP32 253 | // Set pins 254 | // 255 | pinMode(DigitalOutPin, OUTPUT); 256 | ledcSetup(LEDOut_LEDCh, LEDOut_Freq, LEDOut_Bits); 257 | ledcAttachPin(LEDOutPin, LEDOut_LEDCh); 258 | ledcSetup(AnalogOut_LEDCh, AnalogOut_Freq, AnalogOut_Bits); 259 | ledcAttachPin(AnalogOutPin, AnalogOut_LEDCh); 260 | 261 | // Initialize SPI interface for MCP3208 and MCP23S08 262 | // 263 | pinMode(ADC_CS, OUTPUT); 264 | digitalWrite(ADC_CS, HIGH); 265 | pinMode(DIO_CS, OUTPUT); 266 | digitalWrite(DIO_CS, HIGH); 267 | SPISettings settingsHSPI(ADC_CLK, MSBFIRST, SPI_MODE0); 268 | hspi->begin(ADC_SCK, ADC_MISO, ADC_MOSI, ADC_CS); 269 | hspi->beginTransaction(settingsHSPI); 270 | for(int i=0; i<8; i++) { 271 | ADCData[0][0] = 0; 272 | ADCData[0][1] = 0; 273 | } 274 | dio.begin(); 275 | dio.gpioPinMode(ButtonPin -MCP23S08_FIRST, INPUT); 276 | dio.gpioPinMode(DigitalIn1Pin -MCP23S08_FIRST, INPUT); 277 | dio.gpioPinMode(DigitalIn2Pin -MCP23S08_FIRST, INPUT); 278 | dio.gpioPinMode(HousekeepLED -MCP23S08_FIRST, OUTPUT); 279 | DIOData = 0; 280 | #endif 281 | 282 | // Initialise a few variables 283 | // 284 | stateHousekeepingLED = false; 285 | iPnt = 0; 286 | dyPlot = SCREEN_HEIGHT -INFO_DY; 287 | dxInfo = SCREEN_WIDTH /(MAX_TRACES +1); 288 | timeStr[0] = 0; 289 | for(int i=0; i= MCP23S08_FIRST) && (pin <= MCP23S08_LAST)) { 319 | // Handle output pins connected to the port expander MCP23S08 320 | // 321 | #ifdef USES_HOUSEKEEPING 322 | dio.gpioDigitalWriteFast(pin -MCP23S08_FIRST, val); 323 | #else 324 | dio.gpioDigitalWrite(pin -MCP23S08_FIRST, val); 325 | #endif 326 | } 327 | else { 328 | // Handle directly to the ESP connected pins 329 | // 330 | switch(pin) { 331 | case DigitalOutPin: 332 | digitalWrite(pin, val); 333 | break; 334 | } 335 | } 336 | } 337 | 338 | 339 | void analogWriteNew(int pin, int val) 340 | { 341 | #ifdef ESP32 342 | switch(pin) { 343 | case LEDOutPin: 344 | ledcWrite(LEDOut_LEDCh, val); 345 | break; 346 | case AnalogOutPin: 347 | ledcWrite(AnalogOut_LEDCh, val); 348 | break; 349 | } 350 | #endif 351 | } 352 | 353 | 354 | int digitalReadNew(uint8_t pin) 355 | { 356 | if((pin >= MCP23S08_FIRST) && (pin <= MCP23S08_LAST)) { 357 | // Currently only input pins connected to the port expander 358 | // MCP23S08 are handled 359 | // 360 | #ifdef USES_HOUSEKEEPING 361 | return (DIOData & 0x01 << (pin -MCP23S08_FIRST)) > 0 ? HIGH : LOW; 362 | #else 363 | return dio.gpioDigitalRead(pin -MCP23S08_FIRST) > 0 ? HIGH : LOW; 364 | #endif 365 | } 366 | return LOW; 367 | } 368 | 369 | 370 | int analogReadNew(int pin) 371 | { 372 | uint16_t res = 0; 373 | 374 | if((pin >= MCP3208_FIRST) && (pin <= MCP3208_LAST)) { 375 | // Currently only input pins connected to A/D IC MCP3208 are handeled 376 | // 377 | switch (pin) { 378 | case Syn1PotPin: 379 | res = 300; 380 | break; 381 | case Syn2PotPin: 382 | res = 128; 383 | break; 384 | case AnalogInPin: 385 | res = 100; 386 | break; 387 | 388 | default: 389 | #ifdef USES_HOUSEKEEPING 390 | res = ADCData[pin -MCP3208_FIRST][1] >> 2; 391 | #else 392 | // *** TODO *** 393 | #endif 394 | } 395 | } 396 | return res; 397 | } 398 | 399 | // ----------------------------------------------------------------------------- 400 | // Housekeeping routine, to be called once per loop 401 | // ----------------------------------------------------------------------------- 402 | void housekeeping() 403 | { 404 | uint16_t v; 405 | uint8_t iCh; 406 | 407 | // Read A/D channels from MCP3208 and store data 408 | // 409 | for(iCh=0; iCh<3; iCh++) { 410 | v = adc.read(MCP3208::Channel(iCh | 0b1000)); 411 | if((v > 4066) || (v < 30)) { 412 | ADCData[iCh][1] = ADCData[iCh][0]; 413 | } 414 | else { 415 | ADCData[iCh][0] = v; 416 | ADCData[iCh][1] = v; 417 | } 418 | } 419 | 420 | // Flash housekeeping LED, if defined 421 | // 422 | #ifdef HousekeepLED 423 | digitalWriteNew(HousekeepLED, stateHousekeepingLED); 424 | stateHousekeepingLED = !stateHousekeepingLED; 425 | #endif 426 | 427 | // Refresh MCP23S08 and retrieve data 428 | // 429 | DIOData = dio.readGpioPort(); 430 | dio.gpioPortUpdate(); 431 | } 432 | 433 | // ----------------------------------------------------------------------------- 434 | // Graphics 435 | // ----------------------------------------------------------------------------- 436 | int getYCoord(int iTr, float v) 437 | { 438 | // Convert the value into a coordinate on the screen 439 | // 440 | return SCREEN_HEIGHT -1 -map(round(v), TracesMinMax[iTr][0], TracesMinMax[iTr][1], 0, dyPlot); 441 | } 442 | 443 | 444 | void plot(output_t* Output) 445 | { 446 | int y, iTr; 447 | 448 | // Depending on selected trace set, add data to trace array 449 | // 450 | switch(TraceSet) { 451 | case 0: 452 | default: 453 | Traces[0][iPnt] = getYCoord(0, Output->v); 454 | Traces[1][iPnt] = getYCoord(1, Output->I_total); 455 | Traces[2][iPnt] = getYCoord(2, Output->Stim_State); 456 | } 457 | 458 | // Draw new piece of each trace 459 | // 460 | if(iPnt > 0) { 461 | #ifndef USES_FULL_REDRAW 462 | gfx.setColor(0); 463 | gfx.drawLine(iPnt, 0, iPnt, dyPlot); 464 | #endif 465 | for(iTr=0; iTr= MAX_VALUES) { 473 | // Set trace data pointer to the beginning of the array and clear screen 474 | // 475 | iPnt = 0; 476 | #ifndef USES_FULL_REDRAW 477 | gfx.setColor(0); 478 | gfx.drawLine(0, 0, 0, dyPlot); 479 | #else 480 | gfx.fillBuffer(0); 481 | #endif 482 | 483 | // Redraw info area 484 | // 485 | for(iTr=0; iTrNeuronBehaviour, Output->currentMicros /1E6); 498 | gfx.setColor(1); 499 | gfx.drawString(dxInfo/2, dyPlot, timeStr); 500 | 501 | // Commit graph commands 502 | // 503 | gfx.commit(); 504 | } 505 | } 506 | 507 | // ----------------------------------------------------------------------------- 508 | -------------------------------------------------------------------------------- /Arduino/Spikeling/Spikeling.ino: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Spikeling v1.1. By T Baden, Sussex Neuroscience, UK (www.badenlab.org) // 3 | // 2017 // 4 | // Izhikevich model taken from original paper (2003 IEEE) // 5 | //////////////////////////////////////////////////////////////////////////// 6 | // Hardware-specific settings 7 | // Swap these if the ESP32is used instead of Arduino Nano 8 | // (for Spikeling 2.0, see GitHub/Manual) 9 | // 10 | #include "SettingsArduino.h" 11 | //#include "SettingsESP.h" 12 | 13 | /////////////////////////////////////////////////////////////////////////// 14 | // KEY PARAMETERS TO SET BY USER ///////////////////////////////////////// 15 | /////////////////////////////////////////////////////////////////////////// 16 | 17 | int nosound = 0; // 0 default, click on spike + digi out port active. 1 switches both off 18 | int noled = 0; // 0 default, 1 switches the LED off 19 | int FastMode = 0; // default 0; if >0, the script is more optimised for speed by removing some of the serial outputs at the 20 | // ... end of the script. This will systematically speed up the whole thing, but the system time will no longer be output as the 8th column 21 | // ... meaning that the analysis scripts would need to be adjusted to reflect this (i.e. the array entry of the system time, default - column 8). 22 | // FastMode = 0: Stores 8 model parameters via serial, runs at ~280 Hz, system time in column 8 (of 8) 23 | // FastMode = 1: Stores 4 model parameters via serial, runs at ~390 Hz, system time in column 4 (of 4) 24 | // FastMode = 2: Stores 2 model parameters via serial, runs at ~480 Hz, system time in column 2 (of 2) 25 | // FastMode = 3: Stores 0 model parameters via serial, runs at ~730 Hz, DOES NOT SEND DATA TO PC! 26 | // The next best thing to furhter increase speed would be to call the several analog.read/write functions 27 | // less frequently. If all are disabled, the mode can exceed 1kHz, but then the dials/PD don't work... One compromise 28 | // around this would be to call them less frequently. This would give a little extra speed but eventually make the 29 | // dials and photodiode feel "sluggish". The latter is currently not implemented 30 | int AnalogInActive = 1; // default = 1, PORT 3 setting: Is Analog In port in use? Note that this shares the dial with the Syn2 (PORT 2) dial 31 | int Syn1Mode = 1; // default 1 32 | // Syn1Mode = 0: Synapse 1 Port works like Synapse 2, to receive digital pulses as inputs 33 | // Syn1Mode = 1: Synapse 1 Port acts as a Stimulus generator, with pulse frequency being controlled by Syn1Dial 34 | // Syn1Mode = 2: Synapse 1 Port acts as a Stimulus generator, generating random Noise sequences (for reverse correlation) 35 | // Note: this is being read into the Array_DigiOutMode Array below. This can also be manually set for each Mode, if desired by 36 | // simply replacing the Syn1Mode entries in this array with 0, 1 or 2 37 | 38 | float PD_Scaling = 0.5; // the lower the more sensitive. Default = 0.5 39 | int SynapseScaling = 50; // The lower, the stronger the synapse. Default = 50 40 | int VmPotiScaling = 2; // the lower, the stronger the impact of the Vm poti. Default = 2 41 | int AnalogInScaling = 2500; // the lower, the stronger the impact of Analog Input. Default = 2500 42 | int NoiseScaling = 10; // the lower, the higher the default noise level. Default = 10 43 | 44 | float Synapse_decay = 0.995;// speed of synaptic decay.The difference to 1 matters - the smaller the difference, the slower the decay. Default = 0.995 45 | float PD_gain_min = 0.0; // the photodiode gain cannot decay below this value 46 | float timestep_ms = 0.1; // default 0.1. This is the "intended" refresh rate of the model. 47 | // Note that it does not actually run this fast as the Arduino cannot execute the... 48 | // ...full script at this rate. Instead, it will run at 333-900 Hz, depending on settings (see top) 49 | 50 | // set up Neuron behaviour array parameters 51 | int nModes = 5; // set this to number of entries in each array. Entries 1 define Mode 1, etc.. 52 | 53 | // Izhikevich model parameters - for some pre-tested behaviours from the original paper, see bottom of the script 54 | float Array_a[] = { 0.02, 0.02, 0.02, 0.02, 0.02 }; // time scale of recovery variable u. Smaller a gives slower recovery 55 | float Array_b[] = { 0.20, 0.20, 0.25, 0.20, -0.1 }; // recovery variable associated with u. greater b coules it more strongly (basically sensitivity) 56 | int Array_c[] = { -65, -50, -55, -55, -55 }; // after spike reset value 57 | float Array_d[] = { 6.0, 2.0, 0.05, 4.0, 6.0 }; // after spike reset of recovery variable 58 | 59 | float Array_PD_decay[] = { 0.00005, 0.001, 0.00005, 0.001, 0.00005 }; // slow/fast adapting Photodiode - small numbers make diode slow to decay 60 | float Array_PD_recovery[] = { 0.001, 0.01, 0.001, 0.01, 0.001 }; // slow/fast adapting Photodiode - small numbers make diode recover slowly 61 | int Array_PD_polarity[] = { 1, -1, -1, 1, 1 }; // 1 or -1, flips photodiode polarity, i.e. 1: ON cell, 2: OFF cell 62 | 63 | int Array_DigiOutMode[] = {Syn1Mode,Syn1Mode,Syn1Mode,Syn1Mode,Syn1Mode}; // PORT 1 setting. 0: Synapse 1 In, 1: Stimulus out, 2: 50 Hz binary noise out (for reverse correlation) 64 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 65 | // MAIN PROGRAMME - ONLY CHANGE IF YOU KNOW WHAT YOU ARE DOING ! // 66 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 67 | 68 | //////////////////////////////////////////////////////////////////////////// 69 | // Setup variables required to drive the model 70 | float I_total; // Total input current to the model 71 | float I_PD; // Photodiode current 72 | float I_Vm; // Vm setting current 73 | float I_Synapse; // Total synaptic current of both synapses 74 | float I_AnalogIn; // Current from analog Input 75 | float I_Noise; // Noise current 76 | float Synapse1Ampl; // Synapse 1 efficacy 77 | float Synapse2Ampl; // Synapse 2 efficacy 78 | float AnalogInAmpl; // Analog In efficacy 79 | float NoiseAmpl; // Added Noise level 80 | long ModelpreviousMicros = 0; 81 | 82 | // initialise state variables for different inputs 83 | boolean spike = false; 84 | int buttonState = 0; 85 | int SpikeIn1State = 0; 86 | int SpikeIn2State = 0; 87 | int VmPotVal = 0; 88 | float Syn1PotVal = 0.0; 89 | float Syn2PotVal = 0.0; 90 | float NoisePotVal = 0.0; 91 | float AnalogInPotVal = 0.0; 92 | float AnalogInVal = 0.0; 93 | int PDVal = 0; 94 | int Stimulator_Val = 0; 95 | 96 | // for PD smoothing // this is a dirty hack to smooth the photodiode current which in raw form generates ugly noise spikes 97 | int PDVal_Array[] = {0,0,0,0,0,0,0,0,0,0}; 98 | int PD_integration_counter= 0; 99 | float PDVal_smoothed = 0; 100 | 101 | float PD_gain = 1.0; 102 | int NeuronBehaviour = 0; // 0:8 for different modes, cycled by button 103 | int DigiOutStep = 0; // stimestep counter for stimulator mode 104 | int Stim_State = 0; // State of the internal stimulator 105 | float v; // voltage in Iziekevich model 106 | float u; // recovery variable in Iziekevich model 107 | 108 | output_t Output; // output structure for plotting 109 | String OutputStr; 110 | 111 | int startMicros = micros(); 112 | 113 | //////////////////////////////////////////////////////////////////////////// 114 | // SETUP (this only runs once at when the Arduino is initialised) ////////// 115 | //////////////////////////////////////////////////////////////////////////// 116 | 117 | void setup(void) { 118 | Serial.begin(SerOutBAUD); 119 | initializeHardware(); // Set all the PINs 120 | } 121 | 122 | //////////////////////////////////////////////////////////////////////////// 123 | // MAIN //////////////////////////////////////////////////////////////////// 124 | //////////////////////////////////////////////////////////////////////////// 125 | 126 | void loop(void) { 127 | 128 | // check system time in microseconds 129 | unsigned long currentMicros = micros() - startMicros; 130 | 131 | // do housekeeping, if needed 132 | #ifdef USES_HOUSEKEEPING 133 | housekeeping(); 134 | #endif 135 | 136 | // read button to change spike model 137 | buttonState = digitalReadHelper(ButtonPin); 138 | if (buttonState == HIGH) { 139 | NeuronBehaviour+=1; 140 | if (NeuronBehaviour>=nModes) {NeuronBehaviour=0;} 141 | Serial.print("Neuron Mode:"); 142 | Serial.println(NeuronBehaviour); 143 | for (int modeblink = 0; modeblink < NeuronBehaviour +1; modeblink++) { 144 | digitalWriteHelper(LED_BUILTIN, HIGH); // Blinks the onboard LED according to which programme is selected 145 | delay(150); 146 | digitalWriteHelper(LED_BUILTIN, LOW); 147 | delay(150); 148 | } 149 | if (Array_DigiOutMode[NeuronBehaviour]==0) { 150 | pinModeHelper(DigitalIn1Pin, INPUT); // SET SYNAPSE 1 IN AS INTENDED 151 | } else { 152 | pinModeHelper(DigitalIn1Pin, OUTPUT); // SET SYNAPSE 1 IN AS STIMULATOR OUT CHANNEL 153 | } 154 | } 155 | 156 | // NOTE: the below analogRead functions take some microseconds to execute so to speed up the model they 157 | // could be called less frequently or removed entirely. 158 | // To remove them, simply change e.g. PotVal = analogRead(VmPotPin); to PotVal = 512; 159 | 160 | // read Vm potentiometer to calculate I_Vm 161 | VmPotVal = analogReadHelper(VmPotPin); // 0:1023, Vm 162 | I_Vm = -1 * (VmPotVal-512) / VmPotiScaling; 163 | 164 | // read analog In potentiometer to set Analog in and Noise scaling 165 | AnalogInPotVal = analogReadHelper(Syn2PotPin); // 0:1023, Vm - reads same pot as Synapse 2! 166 | AnalogInAmpl = (AnalogInPotVal - 512) / AnalogInScaling; 167 | 168 | NoisePotVal = analogReadHelper(NoisePotPin); // 0:1023, Vm 169 | NoiseAmpl = -1 * ((NoisePotVal-512) / NoiseScaling); 170 | if (NoiseAmpl<0) {NoiseAmpl = 0;} 171 | I_Noise+=random(-NoiseAmpl/2,NoiseAmpl/2); 172 | I_Noise*=0.9; 173 | 174 | // read analog in to calculate I_AnalogIn 175 | AnalogInVal = analogReadHelper(AnalogInPin); // 0:1023 176 | I_AnalogIn = -1 * (AnalogInVal) * AnalogInAmpl; 177 | if (AnalogInActive == 0) {I_AnalogIn = 0;} 178 | 179 | 180 | // read Photodiode 181 | int PDVal = analogReadHelper(PhotoDiodePin); // 0:1023 182 | if (PD_integration_counter<10) { // PD integration over 5 points 183 | PD_integration_counter+=1; 184 | } else { 185 | PD_integration_counter=0; 186 | } 187 | PDVal_Array[PD_integration_counter]=PDVal; 188 | PDVal_smoothed=(PDVal_Array[0]+PDVal_Array[1]+PDVal_Array[2]+PDVal_Array[3]+PDVal_Array[4]+PDVal_Array[5]+PDVal_Array[6]+PDVal_Array[7]+PDVal_Array[8]+PDVal_Array[9])/10; // dirty hack to smooth PD current - could be a lot more elegant 189 | I_PD = ((PDVal_smoothed) / PD_Scaling) * PD_gain; // input current 190 | 191 | if (PD_gain>PD_gain_min){ 192 | PD_gain-=Array_PD_decay[NeuronBehaviour]*I_PD; // adapts proportional to I_PD 193 | if (PD_gain0){ 210 | SpikeIn1State = LOW; 211 | } 212 | SpikeIn2State = digitalReadHelper(DigitalIn2Pin); 213 | if (SpikeIn1State == HIGH) {I_Synapse+=Synapse1Ampl;} 214 | if (SpikeIn2State == HIGH) {I_Synapse+=Synapse2Ampl;} 215 | 216 | // Decay all synaptic current towards zero 217 | I_Synapse*=Synapse_decay; 218 | 219 | // compute Izhikevich model 220 | float I_total = I_PD*Array_PD_polarity[NeuronBehaviour] + I_Vm + I_Synapse + I_AnalogIn + I_Noise; // Add up all current sources 221 | v = v + timestep_ms*(0.04 * v * v + 5*v + 140 - u + I_total); 222 | u = u + timestep_ms*(Array_a[NeuronBehaviour] * ( Array_b[NeuronBehaviour]*v - u)); 223 | if (v>=30.0){v=Array_c[NeuronBehaviour]; u+=Array_d[NeuronBehaviour];} 224 | if (v<=-90) {v=-90.0;} // prevent from analog out (below) going into overdrive - but also means that it will flatline at -90. Change the "90" in this line and the one below if want to 225 | int AnalogOutValue = (v+90) * 2; 226 | analogWriteHelper(AnalogOutPin,AnalogOutValue); 227 | 228 | #ifdef USES_DAC 229 | dacWriteHelper(DACOutPin, uint8_t(map(v, -90,20, 0,255))); 230 | #endif 231 | 232 | if (noled==0) { 233 | analogWriteHelper(LEDOutPin,AnalogOutValue); 234 | } 235 | if (v>-30.0) {spike=true;} // check if there has been a spike for digi out routine (below) 236 | 237 | // trigger audio click and Digi out 5V pulse if there has been a spike 238 | if (spike==true) { 239 | if (nosound==0) { 240 | digitalWriteHelper(DigitalOutPin, HIGH); 241 | } 242 | spike=false; 243 | } 244 | else { 245 | digitalWriteHelper(DigitalOutPin, LOW); 246 | } 247 | 248 | 249 | // Set DigiOut level if Array_DigiOutMode[NeuronBehaviour] is not 0 250 | if (Array_DigiOutMode[NeuronBehaviour]==1){ // if in Step Mode 251 | if (DigiOutStep=Stimulator_Val*2) { 260 | DigiOutStep = 0; 261 | Stimulator_Val = round((Syn1PotVal/1023) * 100); // also calculate 0-100 range variable in case Synapse 1 input is used as stimulator instead 262 | 263 | Stimulator_Val = Stimulator_Val * 10; 264 | if (Stimulator_Val<10) {Stimulator_Val=10;} 265 | 266 | } // the *2 sets duty cycle to 50 %. higher multipliers reduce duty cycle 267 | } 268 | if (Array_DigiOutMode[NeuronBehaviour]==2){ // if in Noise Mode 269 | int randNumber = random(100); 270 | if (randNumber<50) {digitalWriteHelper(DigitalIn1Pin, LOW); Stim_State = 0;} 271 | if (randNumber>=50) {digitalWriteHelper(DigitalIn1Pin, HIGH); Stim_State = 1;} 272 | } 273 | 274 | // Serial output in order 275 | 276 | /*if (FastMode<3){ 277 | // Oscilloscope 1 278 | Serial.print(v); // Ch1: voltage 279 | Serial.print(", "); 280 | } 281 | if (FastMode<2){ 282 | Serial.print(I_total); // Ch2: Total input current 283 | Serial.print(", "); 284 | Serial.print(Stim_State); // Ch3: Internal Stimulus State (if Synapse 1 mode >0) 285 | Serial.print(", "); 286 | } 287 | if (FastMode<1){ 288 | // Oscilloscope 2 289 | Serial.print(SpikeIn1State); // Ch4: State of Synapse 1 (High/Low) 290 | Serial.print(", "); 291 | Serial.print(SpikeIn2State); // Ch5: State of Synapse 2 (High/Low) 292 | Serial.print(", "); 293 | Serial.print(I_PD); // Ch6: Total Photodiode current 294 | Serial.print(", "); 295 | 296 | // Oscilloscope 3 297 | Serial.print(I_AnalogIn); // Ch7: Total Analog In current 298 | Serial.print(", "); 299 | Serial.print(I_Synapse); // Ch8: Total Synaptic Current 300 | Serial.print(", "); 301 | } 302 | if (FastMode<3){ 303 | Serial.print(currentMicros); // Ch9: System Time in us 304 | Serial.println("\r"); 305 | }*/ 306 | 307 | if (FastMode<3){ 308 | // Oscilloscope 1 309 | OutputStr = v; // Ch1: voltage 310 | OutputStr += ", "; 311 | } 312 | if (FastMode<2){ 313 | OutputStr += I_total; // Ch2: Total input current 314 | OutputStr += ", "; 315 | OutputStr += Stim_State; // Ch3: Internal Stimulus State (if Synapse 1 mode >0) 316 | OutputStr += ", "; 317 | } 318 | if (FastMode<1){ 319 | // Oscilloscope 2 320 | OutputStr += SpikeIn1State; // Ch4: State of Synapse 1 (High/Low) 321 | OutputStr += ", "; 322 | OutputStr += SpikeIn2State; // Ch5: State of Synapse 2 (High/Low) 323 | OutputStr += ", "; 324 | OutputStr += I_PD; // Ch6: Total Photodiode current 325 | OutputStr += ", "; 326 | 327 | // Oscilloscope 3 328 | OutputStr += I_AnalogIn; // Ch7: Total Analog In current 329 | OutputStr += ", "; 330 | OutputStr += I_Synapse; // Ch8: Total Synaptic Current 331 | OutputStr += ", "; 332 | } 333 | if (FastMode<3){ 334 | OutputStr += currentMicros; // Ch9: System Time in us 335 | OutputStr += "\r"; 336 | Serial.println(OutputStr); 337 | } 338 | 339 | #ifdef USES_PLOTTING 340 | // Plot data if display is connected 341 | // 342 | Output.v = v; 343 | Output.I_total = I_total; 344 | Output.I_PD = I_PD; 345 | Output.I_AnalogIn = I_AnalogIn; 346 | Output.I_Synapse = I_Synapse; 347 | Output.Stim_State = Stim_State; 348 | Output.SpikeIn1State = SpikeIn1State; 349 | Output.SpikeIn2State = SpikeIn2State; 350 | Output.currentMicros = currentMicros; 351 | Output.NeuronBehaviour = NeuronBehaviour; 352 | plot(&Output); 353 | #endif 354 | } 355 | 356 | //////////////////////////////////////////////////////////////////////////////////////////////// 357 | 358 | // From Iziekevich.org - see also https://www.izhikevich.org/publications/figure1.pdf: 359 | // 0.02 0.2 -65 6 14 ;... % tonic spiking 360 | // 0.02 0.25 -65 6 0.5 ;... % phasic spiking 361 | // 0.02 0.2 -50 2 15 ;... % tonic bursting 362 | // 0.02 0.25 -55 0.05 0.6 ;... % phasic bursting 363 | // 0.02 0.2 -55 4 10 ;... % mixed mode 364 | // 0.01 0.2 -65 8 30 ;... % spike frequency adaptation 365 | // 0.02 -0.1 -55 6 0 ;... % Class 1 366 | // 0.2 0.26 -65 0 0 ;... % Class 2 367 | // 0.02 0.2 -65 6 7 ;... % spike latency 368 | // 0.05 0.26 -60 0 0 ;... % subthreshold oscillations 369 | // 0.1 0.26 -60 -1 0 ;... % resonator 370 | // 0.02 -0.1 -55 6 0 ;... % integrator 371 | // 0.03 0.25 -60 4 0;... % rebound spike 372 | // 0.03 0.25 -52 0 0;... % rebound burst 373 | // 0.03 0.25 -60 4 0 ;... % threshold variability 374 | // 1 1.5 -60 0 -65 ;... % bistability 375 | // 1 0.2 -60 -21 0 ;... % DAP 376 | // 0.02 1 -55 4 0 ;... % accomodation 377 | // -0.02 -1 -60 8 80 ;... % inhibition-induced spiking 378 | // -0.026 -1 -45 0 80]; % inhibition-induced bursting 379 | -------------------------------------------------------------------------------- /Arduino/Spikeling_ploter/Definitions.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Global definitions 3 | // ----------------------------------------------------------------------------- 4 | #ifndef Definitions_h 5 | #define Definitions_h 6 | 7 | #define ID_V 0 8 | #define ID_I_TOTAL 1 9 | #define ID_I_PD 2 10 | #define ID_I_ANALOG_IN 3 11 | #define ID_I_SYNAPSE 4 12 | #define ID_I_STIM_STATE 5 13 | #define ID_I_SPIKE_IN1_STATE 6 14 | #define ID_I_SPIKE_IN2_STATE 7 15 | #define ID_I_CURR_MICROSS 8 16 | 17 | // Model output structure 18 | // 19 | typedef struct { 20 | float v, I_total, I_PD, I_AnalogIn, I_Synapse; 21 | int Stim_State, SpikeIn1State, SpikeIn2State; 22 | unsigned long currentMicros; 23 | int NeuronBehaviour; 24 | } output_t; 25 | 26 | #endif 27 | // ----------------------------------------------------------------------------- 28 | -------------------------------------------------------------------------------- /Arduino/Spikeling_ploter/SettingsArduino.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------- 2 | // Settings for the Arduino Pro (Mini) 3 | // 4 | // ----------------------------------------------------------------------------- 5 | #define USES_FAST_ADC 6 | //#define USES_PLOTTING 7 | //#define USES_FULL_REDRAW 8 | #define USES_HOUSEKEEPING 9 | //#define USES_DAC 10 | 11 | #include "Definitions.h" 12 | 13 | // ----------------------------------------------------------------------------- 14 | // Pin definitions (simulation-related) 15 | // ----------------------------------------------------------------------------- 16 | #define PhotoDiodePin A0 // Photodiode 17 | #define LEDOutPin 9 // LED 18 | #define ButtonPin 2 // Push button to switch spike modes 19 | #define VmPotPin A3 // Resting membrane potential 20 | #define Syn1PotPin A7 // efficacy synapse 1 21 | #define Syn2PotPin A5 // efficacy synapse 2 22 | #define NoisePotPin A6 // scaling of Noise level 23 | #define DigitalIn1Pin 4 // Synapse 1 Input - expects 5V pulses 24 | #define DigitalIn2Pin 5 // Synapse 2 input - expects 5V pulses 25 | #define AnalogInPin A2 // Analog in- takes 0-5V (positive only) 26 | #define DigitalOutPin 3 // "Axon" - generates 5V pulses 27 | #define AnalogOutPin 11 // Analog out for full spike waveform 28 | 29 | #ifdef USES_HOUSEKEEPING 30 | #define MAX_ADC_DATA 8 31 | #define N_ADC_IND 6 32 | uint16_t ADCData[MAX_ADC_DATA]; 33 | uint8_t iADCData[] = {PhotoDiodePin, VmPotPin, Syn1PotPin, Syn2PotPin, 34 | NoisePotPin, AnalogInPin}; 35 | #endif 36 | 37 | // Digital and analog I/O helper macros 38 | // 39 | #define pinModeHelper(pin, mode) pinMode(pin, mode) 40 | #define digitalReadHelper(pin) digitalRead(pin) 41 | #define digitalWriteHelper(pin, val) digitalWrite(pin, val) 42 | #define analogWriteHelper(pin, val) analogWrite(pin, val) 43 | #ifdef USES_FAST_ADC 44 | #ifdef USES_HOUSEKEEPING 45 | #define analogReadHelper(pin) ADCData[pin -A0] 46 | #else 47 | #define analogReadHelper(pin) ADC_read(pin -A0) 48 | #endif 49 | #else 50 | #define analogReadHelper(pin) analogRead(pin) 51 | #endif 52 | 53 | // Serial out 54 | // 55 | #define SerOutBAUD 234000 56 | //1000000, 230400 57 | 58 | // ----------------------------------------------------------------------------- 59 | // Pin definitions (hardware add-ons) 60 | // ----------------------------------------------------------------------------- 61 | 62 | // ----------------------------------------------------------------------------- 63 | // Other hardware-related definitions 64 | // ----------------------------------------------------------------------------- 65 | // Setting and clearing register bits 66 | // 67 | #ifndef cbi 68 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 69 | #endif 70 | #ifndef sbi 71 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 72 | #endif 73 | #ifndef cli 74 | #define disable_interrupts cli() 75 | #endif 76 | #ifndef sei 77 | #define enable_interrupts sei() 78 | #endif 79 | 80 | // ----------------------------------------------------------------------------- 81 | void ADC_init(void) 82 | { 83 | // Initialise buffers 84 | // 85 | for(uint8_t i=0; i 31 | #include "MiniGrafx.h" 32 | #include "ILI9341_SPI.h" 33 | #include 34 | #include 35 | #include 36 | 37 | // ----------------------------------------------------------------------------- 38 | #define MCP3208_FIRST 100 39 | #define MCP3208_LAST 107 40 | #define MCP23S08_FIRST 110 41 | #define MCP23S08_LAST 117 42 | 43 | // ----------------------------------------------------------------------------- 44 | // Pin definitions (simulation-related) 45 | // ----------------------------------------------------------------------------- 46 | #ifdef ESP8266 47 | #define PhotoDiodePin -1 // Photodiode 48 | #define LEDOutPin -2 // LED 49 | #define ButtonPin -3 // Push button to switch spike modes 50 | #define VmPotPin -4 // Resting membrane potential 51 | #define Syn1PotPin -5 // efficacy synapse 1 52 | #define Syn2PotPin -6 // efficacy synapse 2 53 | #define NoisePotPin -7 // scaling of Noise level 54 | #define DigitalIn1Pin -8 // Synapse 1 Input - expects 5V pulses 55 | #define DigitalIn2Pin -9 // Synapse 2 input - expects 5V pulses 56 | #define AnalogInPin -10 // Analog in- takes 0-5V (positive only) 57 | #define DigitalOutPin -11 // "Axon" - generates 5V pulses 58 | #define AnalogOutPin -12 // Analog out for full spike waveform 59 | #define DACOutPin -13 // NEW Analog out for full spike waveform (analog) 60 | #define HousekeepLED -14 // NEW 61 | 62 | // Digital and analog I/O helper macros 63 | // 64 | #define pinModeHelper(pin, mode) pinModeNew(pin, mode) 65 | #define digitalReadHelper(pin) digitalReadNew(pin) 66 | #define digitalWriteHelper(pin, val) digitalWriteNew(pin, val) 67 | #define analogReadHelper(pin) analogReadNew(pin) 68 | #define analogWriteHelper(pin, val) analogWriteNew(pin, val) 69 | #define dacWriteHelper(pin, val) dummy(pin, val) 70 | #endif 71 | #ifdef ESP32 72 | #define PhotoDiodePin MCP3208_FIRST+2 // -> A0 Photodiode 73 | #define LEDOutPin 21 // -> D9/PWM LED 74 | #define ButtonPin MCP23S08_FIRST+1 // -> 2 Push button to switch spike modes 75 | #define VmPotPin MCP3208_FIRST+0 // -> A3 Resting membrane potential 76 | #define Syn1PotPin MCP3208_FIRST+3 // -> A7 efficacy synapse 1 77 | #define Syn2PotPin MCP3208_FIRST+4 // -> A5 efficacy synapse 2 78 | #define NoisePotPin MCP3208_FIRST+1 // -> A6 scaling of Noise level 79 | #define DigitalIn1Pin MCP23S08_FIRST+2 // -> 4 Synapse 1 Input - expects 5V pulses 80 | #define DigitalIn2Pin MCP23S08_FIRST+3 // -> 5 Synapse 2 input - expects 5V pulses 81 | #define AnalogInPin MCP3208_FIRST+5 // -> A2 Analog in- takes 0-5V (positive only) 82 | #define DigitalOutPin 16 // -> D3/DO "Axon" - generates 5V pulses 83 | #define AnalogOutPin 17 // -> D11/PWM Analog out for full spike waveform 84 | #define DACOutPin A0 // NEW Analog out for full spike waveform (analog) 85 | #define HousekeepLED MCP23S08_FIRST+0 // NEW 86 | 87 | // Digital and analog I/O helper macros 88 | // 89 | #define pinModeHelper(pin, mode) pinModeNew(pin, mode) 90 | #define digitalReadHelper(pin) digitalReadNew(pin) 91 | #define digitalWriteHelper(pin, val) digitalWriteNew(pin, val) 92 | #define analogReadHelper(pin) analogReadNew(pin) 93 | #define analogWriteHelper(pin, val) analogWriteNew(pin, val) 94 | #define dacWriteHelper(pin, val) dacWrite(pin, val) 95 | 96 | // NOTES: 97 | // (1) analogWrite() is not implemented in the ESP32, therefore use ledcXXX() 98 | // functions instead. This requires an LED channel ID (0..15), a frequency 99 | // (not sure what unit that is ...) and a bit depth (up to 16 bits) 100 | // https://github.com/espressif/arduino-esp32/blob/a4305284d085caeddd1190d141710fb6f1c6cbe1/cores/esp32/esp32-hal-ledc.c 101 | // 102 | #define LEDOut_LEDCh 0 103 | #define LEDOut_Freq 31250 104 | #define LEDOut_Bits 8 105 | #define AnalogOut_LEDCh 1 106 | #define AnalogOut_Freq LEDOut_Freq 107 | #define AnalogOut_Bits LEDOut_Bits 108 | // 109 | // (2) analogReadNew() uses the 8-channel ADC MCP3208; therefore instead of 110 | // pins, the mapping to the ADC channels on the chip are defined above, 111 | // It's a 12 bit ADC, therefore the results need to be divided by 4. 112 | // The MCP3208 is connected to the second SPI bus of the ESP (HSPI), while 113 | // the TFT display uses the primary SPI bus (VSPI). This is nescessary to 114 | // be able to run the TFT at a particular frequency, at which the MCP3208 115 | // does not seem to work reliable. 116 | // For pins, see "hardware add-ons" section further below. 117 | #endif 118 | 119 | // Serial out 120 | // (115200=testing; 921600=standard; 1843200=a bit faster but less stable) 121 | // 122 | #define SerOutBAUD 921600 123 | 124 | // ----------------------------------------------------------------------------- 125 | // Pin definitions (hardware add-ons) 126 | // ----------------------------------------------------------------------------- 127 | #ifdef ESP8266 128 | #define TFT_DC D2 129 | #define TFT_CS D1 130 | #define TFT_LED D8 131 | #define TOUCH_CS D3 132 | #define TOUCH_IRQ D4 133 | ADC_MODE(ADC_VCC); 134 | #endif 135 | #ifdef ESP32 136 | #define TFT_DC 33 137 | #define TFT_CS 15 // primary SPI bus (VSPI), client #1 138 | #define TOUCH_CS 32 // primary SPI bus (VSPI), client #2 139 | #define ADC_MISO 23 // secondary SPI bus (HSPI) ... 140 | #define ADC_MOSI 22 141 | #define ADC_SCK 27 142 | #define ADC_CS 13 // secondary SPI bus (HSPI), client #1 143 | #define DIO_CS 4 // secondary SPI bus (HSPI), client #2 144 | #define DIO_ADDR 0x20 // address of MCP23S08 (defined by A0,A1 pins) 145 | #define DIO_INT 36 // interrupt pin of MCP23S08 (not yet used) 146 | #define ADC_VREF 5000 // Vref for A/D 147 | #define ADC_CLK 1600000 // secondary SPI bus (HSPI), clock 148 | //#define ADC_CLK 4000000 // secondary SPI bus (HSPI), clock 149 | 150 | #endif 151 | 152 | // Define colors usable in the paletted 16 color frame buffer 153 | // 154 | uint16_t palette[] = {ILI9341_BLACK, // 0 155 | ILI9341_WHITE, // 1 156 | ILI9341_NAVY, // 2 157 | ILI9341_DARKCYAN, // 3 158 | ILI9341_DARKGREEN, // 4 159 | ILI9341_MAROON, // 5 160 | ILI9341_PURPLE, // 6 161 | ILI9341_OLIVE, // 7 162 | ILI9341_LIGHTGREY, // 8 163 | ILI9341_DARKGREY, // 9 164 | ILI9341_BLUE, // 10 165 | ILI9341_GREEN, // 11 166 | ILI9341_CYAN, // 12 167 | ILI9341_RED, // 13 168 | ILI9341_MAGENTA, // 14 169 | ILI9341_YELLOW}; // 15 170 | 171 | const int SCREEN_WIDTH = 320; 172 | const int SCREEN_HEIGHT = 240; 173 | const int BITS_PER_PIXEL = 4; // 2^4 = 16 colors 174 | const int FONT_HEIGHT = 14; // Standard font 175 | #ifdef ESP8266 176 | const int SCREEN_ORIENT = 3; 177 | #endif 178 | #ifdef ESP32 179 | const int SCREEN_ORIENT = 1; 180 | #endif 181 | 182 | // Initialize the drivers 183 | // 184 | ILI9341_SPI tft = ILI9341_SPI(TFT_CS, TFT_DC); 185 | MiniGrafx gfx = MiniGrafx(&tft, BITS_PER_PIXEL, palette); 186 | Adafruit_STMPE610 ts = Adafruit_STMPE610(TOUCH_CS); 187 | #ifdef ESP32 188 | SPIClass *hspi = new SPIClass(HSPI); 189 | MCP3208 adc(ADC_VREF, ADC_CS, hspi); 190 | uint16_t ADCData[8][2]; 191 | MCP23S08 dio(DIO_CS, DIO_ADDR, 0, hspi); 192 | uint8_t DIOData; 193 | #endif 194 | 195 | // Definitions and variables for plotting 196 | // 197 | #define INFO_DY 20 // Height of info panel 198 | #define MAX_TRACES 3 // Maximal number of traces shown in parallel 199 | #define MAX_VALUES 320 // Maximal trace length 200 | #define PLOT_UPDATE 16 // Redraw screen every # values 201 | 202 | const char* OutputInfoStr[] = {"V_m[mV]", "I_t[pA]", "I_PD[pA]", "I_AI[pA]", 203 | "I_Sy[pA]", "StmSt", "SpIn1", "SpIn2", 204 | "t[us]"}; 205 | 206 | int TraceCols[MAX_TRACES] = {13,11,15}; 207 | int Traces[MAX_TRACES][MAX_VALUES]; 208 | int TracesStrIndex[MAX_TRACES]; 209 | int TraceSet; 210 | float TracesMinMax[MAX_TRACES][2]; 211 | int iPnt, dyPlot, dxInfo; 212 | char timeStr[16]; 213 | bool stateHousekeepingLED; 214 | 215 | // ----------------------------------------------------------------------------- 216 | // Other hardware-related definitions 217 | // ----------------------------------------------------------------------------- 218 | 219 | // ----------------------------------------------------------------------------- 220 | // Helpers 221 | // ----------------------------------------------------------------------------- 222 | void setTraceSet() 223 | { 224 | switch(TraceSet) { 225 | case 0: 226 | default: 227 | TracesStrIndex[0] = ID_V; 228 | TracesMinMax[0][0] = -110; 229 | TracesMinMax[0][1] = 25; 230 | TracesStrIndex[1] = ID_I_TOTAL; 231 | TracesMinMax[1][0] = -250; 232 | TracesMinMax[1][1] = 250; 233 | TracesStrIndex[2] = ID_I_STIM_STATE; 234 | TracesMinMax[2][0] = -50; 235 | TracesMinMax[2][1] = 50; 236 | } 237 | } 238 | 239 | 240 | void initializeHardware() 241 | { 242 | #ifdef ESP8266 243 | // Turn on the background LED of TFT 244 | // 245 | pinMode(TFT_LED, OUTPUT); 246 | digitalWrite(TFT_LED, HIGH); 247 | 248 | // Set pins 249 | // 250 | // ... 251 | #endif 252 | #ifdef ESP32 253 | // Set pins 254 | // 255 | pinMode(DigitalOutPin, OUTPUT); 256 | ledcSetup(LEDOut_LEDCh, LEDOut_Freq, LEDOut_Bits); 257 | ledcAttachPin(LEDOutPin, LEDOut_LEDCh); 258 | ledcSetup(AnalogOut_LEDCh, AnalogOut_Freq, AnalogOut_Bits); 259 | ledcAttachPin(AnalogOutPin, AnalogOut_LEDCh); 260 | 261 | // Initialize SPI interface for MCP3208 and MCP23S08 262 | // 263 | pinMode(ADC_CS, OUTPUT); 264 | digitalWrite(ADC_CS, HIGH); 265 | pinMode(DIO_CS, OUTPUT); 266 | digitalWrite(DIO_CS, HIGH); 267 | SPISettings settingsHSPI(ADC_CLK, MSBFIRST, SPI_MODE0); 268 | hspi->begin(ADC_SCK, ADC_MISO, ADC_MOSI, ADC_CS); 269 | hspi->beginTransaction(settingsHSPI); 270 | for(int i=0; i<8; i++) { 271 | ADCData[0][0] = 0; 272 | ADCData[0][1] = 0; 273 | } 274 | dio.begin(); 275 | dio.gpioPinMode(ButtonPin -MCP23S08_FIRST, INPUT); 276 | dio.gpioPinMode(DigitalIn1Pin -MCP23S08_FIRST, INPUT); 277 | dio.gpioPinMode(DigitalIn2Pin -MCP23S08_FIRST, INPUT); 278 | dio.gpioPinMode(HousekeepLED -MCP23S08_FIRST, OUTPUT); 279 | DIOData = 0; 280 | #endif 281 | 282 | // Initialise a few variables 283 | // 284 | stateHousekeepingLED = false; 285 | iPnt = 0; 286 | dyPlot = SCREEN_HEIGHT -INFO_DY; 287 | dxInfo = SCREEN_WIDTH /(MAX_TRACES +1); 288 | timeStr[0] = 0; 289 | for(int i=0; i= MCP23S08_FIRST) && (pin <= MCP23S08_LAST)) { 319 | // Handle output pins connected to the port expander MCP23S08 320 | // 321 | #ifdef USES_HOUSEKEEPING 322 | dio.gpioDigitalWriteFast(pin -MCP23S08_FIRST, val); 323 | #else 324 | dio.gpioDigitalWrite(pin -MCP23S08_FIRST, val); 325 | #endif 326 | } 327 | else { 328 | // Handle directly to the ESP connected pins 329 | // 330 | switch(pin) { 331 | case DigitalOutPin: 332 | digitalWrite(pin, val); 333 | break; 334 | } 335 | } 336 | } 337 | 338 | 339 | void analogWriteNew(int pin, int val) 340 | { 341 | #ifdef ESP32 342 | switch(pin) { 343 | case LEDOutPin: 344 | ledcWrite(LEDOut_LEDCh, val); 345 | break; 346 | case AnalogOutPin: 347 | ledcWrite(AnalogOut_LEDCh, val); 348 | break; 349 | } 350 | #endif 351 | } 352 | 353 | 354 | int digitalReadNew(uint8_t pin) 355 | { 356 | if((pin >= MCP23S08_FIRST) && (pin <= MCP23S08_LAST)) { 357 | // Currently only input pins connected to the port expander 358 | // MCP23S08 are handled 359 | // 360 | #ifdef USES_HOUSEKEEPING 361 | return (DIOData & 0x01 << (pin -MCP23S08_FIRST)) > 0 ? HIGH : LOW; 362 | #else 363 | return dio.gpioDigitalRead(pin -MCP23S08_FIRST) > 0 ? HIGH : LOW; 364 | #endif 365 | } 366 | return LOW; 367 | } 368 | 369 | 370 | int analogReadNew(int pin) 371 | { 372 | uint16_t res = 0; 373 | 374 | if((pin >= MCP3208_FIRST) && (pin <= MCP3208_LAST)) { 375 | // Currently only input pins connected to A/D IC MCP3208 are handeled 376 | // 377 | switch (pin) { 378 | case Syn1PotPin: 379 | res = 300; 380 | break; 381 | case Syn2PotPin: 382 | res = 128; 383 | break; 384 | case AnalogInPin: 385 | res = 100; 386 | break; 387 | 388 | default: 389 | #ifdef USES_HOUSEKEEPING 390 | res = ADCData[pin -MCP3208_FIRST][1] >> 2; 391 | #else 392 | // *** TODO *** 393 | #endif 394 | } 395 | } 396 | return res; 397 | } 398 | 399 | // ----------------------------------------------------------------------------- 400 | // Housekeeping routine, to be called once per loop 401 | // ----------------------------------------------------------------------------- 402 | void housekeeping() 403 | { 404 | uint16_t v; 405 | uint8_t iCh; 406 | 407 | // Read A/D channels from MCP3208 and store data 408 | // 409 | for(iCh=0; iCh<3; iCh++) { 410 | v = adc.read(MCP3208::Channel(iCh | 0b1000)); 411 | if((v > 4066) || (v < 30)) { 412 | ADCData[iCh][1] = ADCData[iCh][0]; 413 | } 414 | else { 415 | ADCData[iCh][0] = v; 416 | ADCData[iCh][1] = v; 417 | } 418 | } 419 | 420 | // Flash housekeeping LED, if defined 421 | // 422 | #ifdef HousekeepLED 423 | digitalWriteNew(HousekeepLED, stateHousekeepingLED); 424 | stateHousekeepingLED = !stateHousekeepingLED; 425 | #endif 426 | 427 | // Refresh MCP23S08 and retrieve data 428 | // 429 | DIOData = dio.readGpioPort(); 430 | dio.gpioPortUpdate(); 431 | } 432 | 433 | // ----------------------------------------------------------------------------- 434 | // Graphics 435 | // ----------------------------------------------------------------------------- 436 | int getYCoord(int iTr, float v) 437 | { 438 | // Convert the value into a coordinate on the screen 439 | // 440 | return SCREEN_HEIGHT -1 -map(round(v), TracesMinMax[iTr][0], TracesMinMax[iTr][1], 0, dyPlot); 441 | } 442 | 443 | 444 | void plot(output_t* Output) 445 | { 446 | int y, iTr; 447 | 448 | // Depending on selected trace set, add data to trace array 449 | // 450 | switch(TraceSet) { 451 | case 0: 452 | default: 453 | Traces[0][iPnt] = getYCoord(0, Output->v); 454 | Traces[1][iPnt] = getYCoord(1, Output->I_total); 455 | Traces[2][iPnt] = getYCoord(2, Output->Stim_State); 456 | } 457 | 458 | // Draw new piece of each trace 459 | // 460 | if(iPnt > 0) { 461 | #ifndef USES_FULL_REDRAW 462 | gfx.setColor(0); 463 | gfx.drawLine(iPnt, 0, iPnt, dyPlot); 464 | #endif 465 | for(iTr=0; iTr= MAX_VALUES) { 473 | // Set trace data pointer to the beginning of the array and clear screen 474 | // 475 | iPnt = 0; 476 | #ifndef USES_FULL_REDRAW 477 | gfx.setColor(0); 478 | gfx.drawLine(0, 0, 0, dyPlot); 479 | #else 480 | gfx.fillBuffer(0); 481 | #endif 482 | 483 | // Redraw info area 484 | // 485 | for(iTr=0; iTrNeuronBehaviour, Output->currentMicros /1E6); 498 | gfx.setColor(1); 499 | gfx.drawString(dxInfo/2, dyPlot, timeStr); 500 | 501 | // Commit graph commands 502 | // 503 | gfx.commit(); 504 | } 505 | } 506 | 507 | // ----------------------------------------------------------------------------- 508 | -------------------------------------------------------------------------------- /Arduino/Spikeling_ploter/Spikeling_ploter.ino: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////// 2 | // Spikeling v1.1. By T Baden, Sussex Neuroscience, UK (www.badenlab.org) // 3 | // 2017 // 4 | // Izhikevich model taken from original paper (2003 IEEE) // 5 | //////////////////////////////////////////////////////////////////////////// 6 | // Hardware-specific settings 7 | // Swap these if the ESP32is used instead of Arduino Nano 8 | // (for Spikeling 2.0, see GitHub/Manual) 9 | // 10 | #include "SettingsArduino.h" 11 | //#include "SettingsESP.h" 12 | 13 | /////////////////////////////////////////////////////////////////////////// 14 | // KEY PARAMETERS TO SET BY USER ///////////////////////////////////////// 15 | /////////////////////////////////////////////////////////////////////////// 16 | 17 | int nosound = 0; // 0 default, click on spike + digi out port active. 1 switches both off 18 | int noled = 0; // 0 default, 1 switches the LED off 19 | int FastMode = 0; // default 0; if >0, the script is more optimised for speed by removing some of the serial outputs at the 20 | // ... end of the script. This will systematically speed up the whole thing, but the system time will no longer be output as the 8th column 21 | // ... meaning that the analysis scripts would need to be adjusted to reflect this (i.e. the array entry of the system time, default - column 8). 22 | // FastMode = 0: Stores 8 model parameters via serial, runs at ~280 Hz, system time in column 8 (of 8) 23 | // FastMode = 1: Stores 4 model parameters via serial, runs at ~390 Hz, system time in column 4 (of 4) 24 | // FastMode = 2: Stores 2 model parameters via serial, runs at ~480 Hz, system time in column 2 (of 2) 25 | // FastMode = 3: Stores 0 model parameters via serial, runs at ~730 Hz, DOES NOT SEND DATA TO PC! 26 | // The next best thing to furhter increase speed would be to call the several analog.read/write functions 27 | // less frequently. If all are disabled, the mode can exceed 1kHz, but then the dials/PD don't work... One compromise 28 | // around this would be to call them less frequently. This would give a little extra speed but eventually make the 29 | // dials and photodiode feel "sluggish". The latter is currently not implemented 30 | int AnalogInActive = 1; // default = 1, PORT 3 setting: Is Analog In port in use? Note that this shares the dial with the Syn2 (PORT 2) dial 31 | int Syn1Mode = 1; // default 1 32 | // Syn1Mode = 0: Synapse 1 Port works like Synapse 2, to receive digital pulses as inputs 33 | // Syn1Mode = 1: Synapse 1 Port acts as a Stimulus generator, with pulse frequency being controlled by Syn1Dial 34 | // Syn1Mode = 2: Synapse 1 Port acts as a Stimulus generator, generating random Noise sequences (for reverse correlation) 35 | // Note: this is being read into the Array_DigiOutMode Array below. This can also be manually set for each Mode, if desired by 36 | // simply replacing the Syn1Mode entries in this array with 0, 1 or 2 37 | 38 | float PD_Scaling = 0.5; // the lower the more sensitive. Default = 0.5 39 | int SynapseScaling = 50; // The lower, the stronger the synapse. Default = 50 40 | int VmPotiScaling = 2; // the lower, the stronger the impact of the Vm poti. Default = 2 41 | int AnalogInScaling = 2500; // the lower, the stronger the impact of Analog Input. Default = 2500 42 | int NoiseScaling = 10; // the lower, the higher the default noise level. Default = 10 43 | 44 | float Synapse_decay = 0.995;// speed of synaptic decay.The difference to 1 matters - the smaller the difference, the slower the decay. Default = 0.995 45 | float PD_gain_min = 0.0; // the photodiode gain cannot decay below this value 46 | float timestep_ms = 0.1; // default 0.1. This is the "intended" refresh rate of the model. 47 | // Note that it does not actually run this fast as the Arduino cannot execute the... 48 | // ...full script at this rate. Instead, it will run at 333-900 Hz, depending on settings (see top) 49 | 50 | // set up Neuron behaviour array parameters 51 | int nModes = 5; // set this to number of entries in each array. Entries 1 define Mode 1, etc.. 52 | 53 | // Izhikevich model parameters - for some pre-tested behaviours from the original paper, see bottom of the script 54 | float Array_a[] = { 0.02, 0.02, 0.02, 0.02, 0.02 }; // time scale of recovery variable u. Smaller a gives slower recovery 55 | float Array_b[] = { 0.20, 0.20, 0.25, 0.20, -0.1 }; // recovery variable associated with u. greater b coules it more strongly (basically sensitivity) 56 | int Array_c[] = { -65, -50, -55, -55, -55 }; // after spike reset value 57 | float Array_d[] = { 6.0, 2.0, 0.05, 4.0, 6.0 }; // after spike reset of recovery variable 58 | 59 | float Array_PD_decay[] = { 0.00005, 0.001, 0.00005, 0.001, 0.00005 }; // slow/fast adapting Photodiode - small numbers make diode slow to decay 60 | float Array_PD_recovery[] = { 0.001, 0.01, 0.001, 0.01, 0.001 }; // slow/fast adapting Photodiode - small numbers make diode recover slowly 61 | int Array_PD_polarity[] = { 1, -1, -1, 1, 1 }; // 1 or -1, flips photodiode polarity, i.e. 1: ON cell, 2: OFF cell 62 | 63 | int Array_DigiOutMode[] = {Syn1Mode,Syn1Mode,Syn1Mode,Syn1Mode,Syn1Mode}; // PORT 1 setting. 0: Synapse 1 In, 1: Stimulus out, 2: 50 Hz binary noise out (for reverse correlation) 64 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 65 | // MAIN PROGRAMME - ONLY CHANGE IF YOU KNOW WHAT YOU ARE DOING ! // 66 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 67 | 68 | //////////////////////////////////////////////////////////////////////////// 69 | // Setup variables required to drive the model 70 | float I_total; // Total input current to the model 71 | float I_PD; // Photodiode current 72 | float I_Vm; // Vm setting current 73 | float I_Synapse; // Total synaptic current of both synapses 74 | float I_AnalogIn; // Current from analog Input 75 | float I_Noise; // Noise current 76 | float Synapse1Ampl; // Synapse 1 efficacy 77 | float Synapse2Ampl; // Synapse 2 efficacy 78 | float AnalogInAmpl; // Analog In efficacy 79 | float NoiseAmpl; // Added Noise level 80 | long ModelpreviousMicros = 0; 81 | 82 | // initialise state variables for different inputs 83 | boolean spike = false; 84 | int buttonState = 0; 85 | int SpikeIn1State = 0; 86 | int SpikeIn2State = 0; 87 | int VmPotVal = 0; 88 | float Syn1PotVal = 0.0; 89 | float Syn2PotVal = 0.0; 90 | float NoisePotVal = 0.0; 91 | float AnalogInPotVal = 0.0; 92 | float AnalogInVal = 0.0; 93 | int PDVal = 0; 94 | int Stimulator_Val = 0; 95 | 96 | // for PD smoothing // this is a dirty hack to smooth the photodiode current which in raw form generates ugly noise spikes 97 | int PDVal_Array[] = {0,0,0,0,0,0,0,0,0,0}; 98 | int PD_integration_counter= 0; 99 | float PDVal_smoothed = 0; 100 | 101 | float PD_gain = 1.0; 102 | int NeuronBehaviour = 0; // 0:8 for different modes, cycled by button 103 | int DigiOutStep = 0; // stimestep counter for stimulator mode 104 | int Stim_State = 0; // State of the internal stimulator 105 | float v; // voltage in Iziekevich model 106 | float u; // recovery variable in Iziekevich model 107 | 108 | output_t Output; // output structure for plotting 109 | String OutputStr; 110 | 111 | int startMicros = micros(); 112 | 113 | //////////////////////////////////////////////////////////////////////////// 114 | // SETUP (this only runs once at when the Arduino is initialised) ////////// 115 | //////////////////////////////////////////////////////////////////////////// 116 | 117 | void setup(void) { 118 | Serial.begin(SerOutBAUD); 119 | initializeHardware(); // Set all the PINs 120 | } 121 | 122 | //////////////////////////////////////////////////////////////////////////// 123 | // MAIN //////////////////////////////////////////////////////////////////// 124 | //////////////////////////////////////////////////////////////////////////// 125 | 126 | void loop(void) { 127 | 128 | // check system time in microseconds 129 | unsigned long currentMicros = micros() - startMicros; 130 | 131 | // do housekeeping, if needed 132 | #ifdef USES_HOUSEKEEPING 133 | housekeeping(); 134 | #endif 135 | 136 | // read button to change spike model 137 | buttonState = digitalReadHelper(ButtonPin); 138 | if (buttonState == HIGH) { 139 | NeuronBehaviour+=1; 140 | if (NeuronBehaviour>=nModes) {NeuronBehaviour=0;} 141 | Serial.print("Neuron Mode:"); 142 | Serial.println(NeuronBehaviour); 143 | for (int modeblink = 0; modeblink < NeuronBehaviour +1; modeblink++) { 144 | digitalWriteHelper(LED_BUILTIN, HIGH); // Blinks the onboard LED according to which programme is selected 145 | delay(150); 146 | digitalWriteHelper(LED_BUILTIN, LOW); 147 | delay(150); 148 | } 149 | if (Array_DigiOutMode[NeuronBehaviour]==0) { 150 | pinModeHelper(DigitalIn1Pin, INPUT); // SET SYNAPSE 1 IN AS INTENDED 151 | } else { 152 | pinModeHelper(DigitalIn1Pin, OUTPUT); // SET SYNAPSE 1 IN AS STIMULATOR OUT CHANNEL 153 | } 154 | } 155 | 156 | // NOTE: the below analogRead functions take some microseconds to execute so to speed up the model they 157 | // could be called less frequently or removed entirely. 158 | // To remove them, simply change e.g. PotVal = analogRead(VmPotPin); to PotVal = 512; 159 | 160 | // read Vm potentiometer to calculate I_Vm 161 | VmPotVal = analogReadHelper(VmPotPin); // 0:1023, Vm 162 | I_Vm = -1 * (VmPotVal-512) / VmPotiScaling; 163 | 164 | // read analog In potentiometer to set Analog in and Noise scaling 165 | AnalogInPotVal = analogReadHelper(Syn2PotPin); // 0:1023, Vm - reads same pot as Synapse 2! 166 | AnalogInAmpl = (AnalogInPotVal - 512) / AnalogInScaling; 167 | 168 | NoisePotVal = analogReadHelper(NoisePotPin); // 0:1023, Vm 169 | NoiseAmpl = -1 * ((NoisePotVal-512) / NoiseScaling); 170 | if (NoiseAmpl<0) {NoiseAmpl = 0;} 171 | I_Noise+=random(-NoiseAmpl/2,NoiseAmpl/2); 172 | I_Noise*=0.9; 173 | 174 | // read analog in to calculate I_AnalogIn 175 | AnalogInVal = analogReadHelper(AnalogInPin); // 0:1023 176 | I_AnalogIn = -1 * (AnalogInVal) * AnalogInAmpl; 177 | if (AnalogInActive == 0) {I_AnalogIn = 0;} 178 | 179 | 180 | // read Photodiode 181 | int PDVal = analogReadHelper(PhotoDiodePin); // 0:1023 182 | if (PD_integration_counter<10) { // PD integration over 5 points 183 | PD_integration_counter+=1; 184 | } else { 185 | PD_integration_counter=0; 186 | } 187 | PDVal_Array[PD_integration_counter]=PDVal; 188 | PDVal_smoothed=(PDVal_Array[0]+PDVal_Array[1]+PDVal_Array[2]+PDVal_Array[3]+PDVal_Array[4]+PDVal_Array[5]+PDVal_Array[6]+PDVal_Array[7]+PDVal_Array[8]+PDVal_Array[9])/10; // dirty hack to smooth PD current - could be a lot more elegant 189 | I_PD = ((PDVal_smoothed) / PD_Scaling) * PD_gain; // input current 190 | 191 | if (PD_gain>PD_gain_min){ 192 | PD_gain-=Array_PD_decay[NeuronBehaviour]*I_PD; // adapts proportional to I_PD 193 | if (PD_gain0){ 210 | SpikeIn1State = LOW; 211 | } 212 | SpikeIn2State = digitalReadHelper(DigitalIn2Pin); 213 | if (SpikeIn1State == HIGH) {I_Synapse+=Synapse1Ampl;} 214 | if (SpikeIn2State == HIGH) {I_Synapse+=Synapse2Ampl;} 215 | 216 | // Decay all synaptic current towards zero 217 | I_Synapse*=Synapse_decay; 218 | 219 | // compute Izhikevich model 220 | float I_total = I_PD*Array_PD_polarity[NeuronBehaviour] + I_Vm + I_Synapse + I_AnalogIn + I_Noise; // Add up all current sources 221 | v = v + timestep_ms*(0.04 * v * v + 5*v + 140 - u + I_total); 222 | u = u + timestep_ms*(Array_a[NeuronBehaviour] * ( Array_b[NeuronBehaviour]*v - u)); 223 | if (v>=30.0){v=Array_c[NeuronBehaviour]; u+=Array_d[NeuronBehaviour];} 224 | if (v<=-90) {v=-90.0;} // prevent from analog out (below) going into overdrive - but also means that it will flatline at -90. Change the "90" in this line and the one below if want to 225 | int AnalogOutValue = (v+90) * 2; 226 | analogWriteHelper(AnalogOutPin,AnalogOutValue); 227 | 228 | #ifdef USES_DAC 229 | dacWriteHelper(DACOutPin, uint8_t(map(v, -90,20, 0,255))); 230 | #endif 231 | 232 | if (noled==0) { 233 | analogWriteHelper(LEDOutPin,AnalogOutValue); 234 | } 235 | if (v>-30.0) {spike=true;} // check if there has been a spike for digi out routine (below) 236 | 237 | // trigger audio click and Digi out 5V pulse if there has been a spike 238 | if (spike==true) { 239 | if (nosound==0) { 240 | digitalWriteHelper(DigitalOutPin, HIGH); 241 | } 242 | spike=false; 243 | } 244 | else { 245 | digitalWriteHelper(DigitalOutPin, LOW); 246 | } 247 | 248 | 249 | // Set DigiOut level if Array_DigiOutMode[NeuronBehaviour] is not 0 250 | if (Array_DigiOutMode[NeuronBehaviour]==1){ // if in Step Mode 251 | if (DigiOutStep=Stimulator_Val*2) { 260 | DigiOutStep = 0; 261 | Stimulator_Val = round((Syn1PotVal/1023) * 100); // also calculate 0-100 range variable in case Synapse 1 input is used as stimulator instead 262 | 263 | Stimulator_Val = Stimulator_Val * 10; 264 | if (Stimulator_Val<10) {Stimulator_Val=10;} 265 | 266 | } // the *2 sets duty cycle to 50 %. higher multipliers reduce duty cycle 267 | } 268 | if (Array_DigiOutMode[NeuronBehaviour]==2){ // if in Noise Mode 269 | int randNumber = random(100); 270 | if (randNumber<50) {digitalWriteHelper(DigitalIn1Pin, LOW); Stim_State = 0;} 271 | if (randNumber>=50) {digitalWriteHelper(DigitalIn1Pin, HIGH); Stim_State = 1;} 272 | } 273 | 274 | // Serial output in order 275 | 276 | /*if (FastMode<3){ 277 | // Oscilloscope 1 278 | Serial.print(v); // Ch1: voltage 279 | Serial.print(", "); 280 | } 281 | if (FastMode<2){ 282 | Serial.print(I_total); // Ch2: Total input current 283 | Serial.print(", "); 284 | Serial.print(Stim_State); // Ch3: Internal Stimulus State (if Synapse 1 mode >0) 285 | Serial.print(", "); 286 | } 287 | if (FastMode<1){ 288 | // Oscilloscope 2 289 | Serial.print(SpikeIn1State); // Ch4: State of Synapse 1 (High/Low) 290 | Serial.print(", "); 291 | Serial.print(SpikeIn2State); // Ch5: State of Synapse 2 (High/Low) 292 | Serial.print(", "); 293 | Serial.print(I_PD); // Ch6: Total Photodiode current 294 | Serial.print(", "); 295 | 296 | // Oscilloscope 3 297 | Serial.print(I_AnalogIn); // Ch7: Total Analog In current 298 | Serial.print(", "); 299 | Serial.print(I_Synapse); // Ch8: Total Synaptic Current 300 | Serial.print(", "); 301 | } 302 | if (FastMode<3){ 303 | Serial.print(currentMicros); // Ch9: System Time in us 304 | Serial.println("\r"); 305 | }*/ 306 | 307 | if (FastMode<3){ 308 | // Oscilloscope 1 309 | OutputStr = v; // Ch1: voltage 310 | OutputStr += ", "; 311 | } 312 | if (FastMode<2){ 313 | OutputStr += I_total; // Ch2: Total input current 314 | OutputStr += ", "; 315 | OutputStr += Stim_State; // Ch3: Internal Stimulus State (if Synapse 1 mode >0) 316 | OutputStr += ", "; 317 | } 318 | if (FastMode<1){ 319 | // Oscilloscope 2 320 | OutputStr += SpikeIn1State; // Ch4: State of Synapse 1 (High/Low) 321 | OutputStr += ", "; 322 | OutputStr += SpikeIn2State; // Ch5: State of Synapse 2 (High/Low) 323 | OutputStr += ", "; 324 | OutputStr += I_PD; // Ch6: Total Photodiode current 325 | OutputStr += ", "; 326 | 327 | // Oscilloscope 3 328 | OutputStr += I_AnalogIn; // Ch7: Total Analog In current 329 | OutputStr += ", "; 330 | OutputStr += I_Synapse; // Ch8: Total Synaptic Current 331 | OutputStr += ", "; 332 | } 333 | if (FastMode<3){ 334 | OutputStr += currentMicros; // Ch9: System Time in us 335 | OutputStr += "\r"; 336 | //Serial.println(OutputStr); 337 | Serial.print("v "); 338 | Serial.print(v); 339 | Serial.print(" "); 340 | Serial.print("I "); 341 | Serial.println(I_total); 342 | } 343 | 344 | #ifdef USES_PLOTTING 345 | // Plot data if display is connected 346 | // 347 | Output.v = v; 348 | Output.I_total = I_total; 349 | Output.I_PD = I_PD; 350 | Output.I_AnalogIn = I_AnalogIn; 351 | Output.I_Synapse = I_Synapse; 352 | Output.Stim_State = Stim_State; 353 | Output.SpikeIn1State = SpikeIn1State; 354 | Output.SpikeIn2State = SpikeIn2State; 355 | Output.currentMicros = currentMicros; 356 | Output.NeuronBehaviour = NeuronBehaviour; 357 | plot(&Output); 358 | #endif 359 | } 360 | 361 | //////////////////////////////////////////////////////////////////////////////////////////////// 362 | 363 | // From Iziekevich.org - see also https://www.izhikevich.org/publications/figure1.pdf: 364 | // 0.02 0.2 -65 6 14 ;... % tonic spiking 365 | // 0.02 0.25 -65 6 0.5 ;... % phasic spiking 366 | // 0.02 0.2 -50 2 15 ;... % tonic bursting 367 | // 0.02 0.25 -55 0.05 0.6 ;... % phasic bursting 368 | // 0.02 0.2 -55 4 10 ;... % mixed mode 369 | // 0.01 0.2 -65 8 30 ;... % spike frequency adaptation 370 | // 0.02 -0.1 -55 6 0 ;... % Class 1 371 | // 0.2 0.26 -65 0 0 ;... % Class 2 372 | // 0.02 0.2 -65 6 7 ;... % spike latency 373 | // 0.05 0.26 -60 0 0 ;... % subthreshold oscillations 374 | // 0.1 0.26 -60 -1 0 ;... % resonator 375 | // 0.02 -0.1 -55 6 0 ;... % integrator 376 | // 0.03 0.25 -60 4 0;... % rebound spike 377 | // 0.03 0.25 -52 0 0;... % rebound burst 378 | // 0.03 0.25 -60 4 0 ;... % threshold variability 379 | // 1 1.5 -60 0 -65 ;... % bistability 380 | // 1 0.2 -60 -21 0 ;... % DAP 381 | // 0.02 1 -55 4 0 ;... % accomodation 382 | // -0.02 -1 -60 8 80 ;... % inhibition-induced spiking 383 | // -0.026 -1 -45 0 80]; % inhibition-induced bursting 384 | -------------------------------------------------------------------------------- /Bill of Materials (BOM).xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/Bill of Materials (BOM).xlsx -------------------------------------------------------------------------------- /Example recorded data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/Example recorded data.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Baden Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MATLAB scripts/spikelingFunctions - Kernels.m: -------------------------------------------------------------------------------- 1 | 2 | function spikelingFunctions(filename) 3 | %% Main spikeling function 4 | dat = loadSpikelingData(filename); % load data 5 | dat = findSpikes(dat); % find spike times 6 | dat = convertToFreqISI(dat); % compute instantaenous freq 7 | dat = checkStim(dat); % check if stimulus is present 8 | plotall(dat) % plot main function 9 | eventPlot = plotEventsQuest(); 10 | if dat.stim.stimPres==1&& eventPlot==1 % if stimulus present, plot stimulus things 11 | dat = eventThings(dat); 12 | plotEvents(dat) 13 | end 14 | dat = sta(dat); 15 | dat = subThresh(dat); 16 | plotSTA(dat); 17 | save spikeDat % save outputs 18 | end 19 | 20 | 21 | function eventPlot = plotEventsQuest() 22 | %%ask if you want to plot event stuff 23 | answer = questdlg('Would you like to plot event-triggered superposition (not recommended for large datasets)?', ... 24 | 'Plot', ... 25 | 'Yes', 'No','No'); 26 | % Handle response 27 | switch answer 28 | case 'Yes' 29 | eventPlot = 1; 30 | case 'No' 31 | eventPlot = 0; 32 | end 33 | end 34 | 35 | 36 | 37 | function plotSTA(dat); 38 | 39 | %% 40 | 41 | figure('pos',[900 100 200 600]) 42 | 43 | 44 | set(gcf,'color','white') 45 | subplot(2,1,1) 46 | set(gca,'Xdir','reverse') 47 | 48 | plot(dat.staT,dat.sta,'k') 49 | 50 | set(gca,'fontsize',8) 51 | ylabel('Light','fontsize',10) 52 | box off 53 | 54 | 55 | subplot(2,1,2) 56 | set(gca,'Xdir','reverse') 57 | plot(dat.staT,dat.staCurr,'k') 58 | set(gca,'fontsize',8) 59 | ylabel('Current','fontsize',10) 60 | box off 61 | 62 | % subplot(4,1,3) 63 | % set(gca,'Xdir','reverse') 64 | % plot(dat.staT,dat.subSTA,'k') 65 | % set(gca,'fontsize',8) 66 | % ylabel('Light','fontsize',10) 67 | 68 | 69 | % subplot(4,1,4) 70 | % set(gca,'Xdir','reverse') 71 | % plot(dat.staT,dat.subStaCurr,'k') 72 | % set(gca,'fontsize',8) 73 | % ylabel('Current','fontsize',10) 74 | set(gca,'fontsize',8) 75 | xlabel('Time (s)','fontsize',10) 76 | 77 | 78 | end 79 | 80 | 81 | function dat = subThresh(dat); 82 | %% subthreshold STAA 83 | 84 | spikeThresh = -55; % THreshold to remove spiking activity 85 | subThresh = 1; % Threshold for differentiated voltage 86 | nPts = length(dat.v); 87 | vDiff = zeros(nPts,1); 88 | vDiff(1) = 0; 89 | % Differentiate 90 | for (i=2:nPts) 91 | vDiff(i) = dat.v(i)-dat.v(i-1); 92 | end 93 | % Remove spikes 94 | for (i=1:nPts) 95 | if dat.v(i)> spikeThresh 96 | vDiff(i) = 0; 97 | end 98 | end 99 | 100 | dat.vDiff = vDiff; 101 | % COmpute subSTA 102 | backTime = .5; 103 | backInds = round(backTime/.004); 104 | subSTA = zeros(backInds+1,1); 105 | subStaCurr = subSTA; 106 | nGood = 0; 107 | for i=2:nPts-1 108 | if vDiff(i) > subThresh && vDiff(i-1) < subThresh && i > backInds % when diff crosses subthresh 109 | subSTA = subSTA + (dat.stimState(i-backInds:i).*vDiff(i)); % scale by vlues 110 | subStaCurr = subStaCurr + dat.totC(i-backInds:i).*vDiff(i); 111 | nGood = nGood +vDiff(i); 112 | end 113 | end 114 | %average and save 115 | subSTA = subSTA /nGood; 116 | subStaCurr = subStaCurr / nGood; 117 | dat.subSTA = subSTA; 118 | dat.subStaCurr = subStaCurr; 119 | end 120 | 121 | 122 | 123 | function dat = sta(dat); 124 | %% Make sta 125 | backTime = .5; 126 | backInds = round(backTime/.004); 127 | sta = zeros(backInds+1,1); 128 | staCurr = zeros(backInds+1,1); 129 | nGood = 0; 130 | for i=1:length(dat.spikeInd) 131 | if (dat.spikeInd(i) > backInds) 132 | sta =sta + dat.stimState(dat.spikeInd(i)-backInds:dat.spikeInd(i)); 133 | staCurr = staCurr + dat.totC(dat.spikeInd(i)-backInds:dat.spikeInd(i)); 134 | nGood = nGood+1; 135 | end 136 | end 137 | sta = sta/ nGood; 138 | staCurr = staCurr/ nGood; 139 | dat.sta = sta; 140 | dat.staT = -.5:.004:0; 141 | dat.staCurr = staCurr; 142 | 143 | 144 | 145 | 146 | 147 | 148 | end 149 | 150 | function dat = checkStim(dat); 151 | %% Checks if stim is present 152 | nPts = length(dat.v); 153 | nOns = 0; 154 | for i=2:nPts 155 | if (dat.stimState(i-1)==0 && dat.stimState(i)==1) 156 | nOns= 1; 157 | break 158 | end 159 | end 160 | 161 | dat.stim.stimPres = nOns; 162 | end 163 | 164 | function dat = loadSpikelingData(filename) 165 | %% Load data from csv file saved as filename 166 | 167 | datM = load(filename); % how matlab loads 168 | datMat = sortrows(datM,9); % sort (sometimes the data isn't sorted in time) 169 | % convert data from a matrix to a struct - makes things easier 170 | dat.v = datMat(1:2:end,1); 171 | dat.totC = datMat(1:2:end,2); 172 | dat.stimState = datMat(1:2:end,3); 173 | dat.syn1State = datMat(1:2:end,4); 174 | dat.syn2State = datMat(1:2:end,5); 175 | dat.pdCurrent = datMat(1:2:end,6); 176 | dat.totAnIn = datMat(1:2:end,7); 177 | dat.totSynC = datMat(1:2:end,8); 178 | dat.time = datMat(1:2:end,9)./1000./1000; %converted to seconds 179 | % every other point (spikeling is sending duplicaate values) 180 | dat.time = dat.time - dat.time(1); % set first time to zero 181 | newT = 0:.004:dat.time(end); 182 | 183 | 184 | 185 | end 186 | 187 | function plotall(dat) 188 | disp('Plotting Base Things') 189 | mx =max(dat.v); 190 | figure('pos',[100 100 800 600]) 191 | %% Plot voltage and spikes location markers 192 | set(gcf,'color','white') 193 | ax1 = subplot(4,1,2); 194 | plot(dat.time,dat.v,'k') 195 | hold on 196 | if dat.spikesPres==1 197 | scatter(dat.spikeTimes,mx*ones(1,length(dat.spikeTimes)),2,'k'); 198 | end 199 | set(gca,'fontsize',8) 200 | ylabel('Voltage (mV)','fontsize',10) % edit TB 201 | box off 202 | set(gca,'xtick',[]) 203 | 204 | p1 = get(ax1,'Position'); 205 | %% Plot currents 206 | ax2 = subplot(4,1,3); 207 | plot(dat.time,dat.totC,'k') 208 | box off 209 | set(gca,'xtick',[]) 210 | hold on 211 | plot(dat.time,dat.pdCurrent,'Color',[.25 .25 .25]) 212 | plot(dat.time,dat.totAnIn,'Color',[.5 .5 .5]) 213 | set(gca,'fontsize',8) 214 | ylabel('Currents (AU)','fontsize',10) % edit TB 215 | legend('Total Current','Photodiode Current','Total Analog Input') 216 | p2 = get(ax2,'Position'); 217 | %% Plot frequencies 218 | ax3 = subplot(4,1,1); 219 | p3 = get(ax3,'Position'); 220 | plot(dat.time,dat.spikeFreq,'k') 221 | set(gca,'fontsize',8) 222 | ylabel('Spike Rate (Hz)','fontsize',10) % edit TB 223 | box off 224 | set(gca,'xtick',[]) 225 | 226 | %% Plot synapse and stimulus states 227 | ax4 = subplot(4,1,4); 228 | plot(dat.time,dat.syn1State,'Color',[.5 .5 .5]) 229 | hold on 230 | plot(dat.time,dat.syn2State,'Color',[.25 .25 .25]) 231 | box off 232 | ylim([-0.1,1.1]) 233 | plot(dat.time,dat.stimState,'k') 234 | set(gca,'fontsize',8) 235 | ylabel('Inputs','fontsize',10) 236 | xlabel('Time (s)','fontsize',10) % edit TB 237 | 238 | linkaxes([ax1,ax2,ax3,ax4],'x'); % link axes 239 | % so changing x on one changes all 240 | xlim([0,max(dat.time)]) 241 | 242 | legend('Synapse 1','Synapse 2','Stimulus State') 243 | p4 = get(ax4,'Position'); 244 | 245 | %% Axis Y positions 246 | p3(2) = .8; % rate 247 | p3(4) = .1; % rate height 248 | p1(2) = 0.45; % voltage 249 | p1(4) = .3; % voltage height 250 | p2(2) = 0.2; % currents 251 | p2(4) = .2; % currents height 252 | p4(2) = .1; % stim 253 | p4(4) = .05; % stim height 254 | set(ax1,'pos',p1) 255 | set(ax2,'pos',p2) 256 | set(ax3,'pos',p3) 257 | set(ax4,'pos',p4) 258 | 259 | end 260 | 261 | function dat = findSpikes(dat) 262 | %% Finds spikes 263 | spikeTime = []; % initialize empty vector of spike times (we don't 264 | % know how many spikes a priori 265 | spikeInd = []; % initialize indice vector 266 | thresh = 10; % must be above this value to be considered a spike 267 | nPts = length(dat.time); 268 | tempTrain = zeros(1,nPts); % initialize a spike train as no zeros 269 | for i=1:nPts-1 % loop over points in times 270 | if (dat.v(i) >= thresh && dat.v(i+1) 0 283 | dat.spikesPres = 1; 284 | else 285 | dat.spikesPres = 0; 286 | end 287 | 288 | end 289 | 290 | function dat = eventThings(dat) 291 | %% Finds the points when the stimuli goes from 0 to 1 and pulls stuff 292 | nPts = length(dat.stimState); 293 | dat.stim.v = []; 294 | dat.stim.totC = []; 295 | dat.stim.pdCurrent = []; 296 | dat.stim.totAnIn = []; 297 | dat.stim.meanDT = []; 298 | dat.stim.freq = []; 299 | dat.stim.startInd = []; 300 | dat.stim.spikes = {}; 301 | dat.stim.periCount = []; 302 | for i=2:nPts 303 | if (dat.stimState(i-1)==0 && dat.stimState(i)==1) 304 | dat.stim.startInd(end+1) = i; 305 | end 306 | end 307 | for (i=2:length(dat.stim.startInd)) 308 | interval(i-1) = dat.stim.startInd(i)-dat.stim.startInd(i-1); 309 | end 310 | ptsPull = ceil(mean(interval)); 311 | dat.stim.period = dat.time(ptsPull)-dat.time(1); 312 | 313 | for (i=2:nPts-ptsPull-1) 314 | if (dat.stimState(i-1)==0 && dat.stimState(i)==1) 315 | dat.stim.v(end+1,:) = dat.v(i:i+ptsPull); 316 | dat.stim.totC(end+1,:) = dat.totC(i:i+ptsPull); 317 | dat.stim.pdCurrent(end+1,:) = dat.pdCurrent(i:i+ptsPull); 318 | dat.stim.totAnIn(end+1,:) = dat.totAnIn(i:i+ptsPull); 319 | dat.stim.meanDT(end+1) = (dat.time(i+ptsPull)-dat.time(i))/ptsPull; 320 | dat.stim.freq(end+1,:) = dat.spikeFreq(i:i+ptsPull); 321 | dat.stim.spikes{end+1}(:) = dat.spikeTimes(find(dat.spikeTimes > dat.time(i) & dat.spikeTimes < dat.time(i+ptsPull))); 322 | dat.stim.spikes{end}= dat.stim.spikes{end} - dat.time(i); 323 | dat.stim.periCount(end+1) = length(dat.stim.spikes{end}); 324 | end 325 | end 326 | periCountMax = max(dat.stim.periCount); 327 | for i=1:periCountMax+1 328 | dat.stim.pCount(i) = length(find(dat.stim.periCount==(i-1)))/length(dat.stim.periCount); 329 | end 330 | 331 | dat.stim.allSpikes = cell2mat(dat.stim.spikes) ; 332 | 333 | 334 | 335 | 336 | %% Finds when syn1 goes from zero to ones, pulls stuff 337 | dat.syn1.v = []; 338 | dat.syn1.totC = []; 339 | dat.syn1.pdCurrent = []; 340 | dat.syn1.totAnIn = []; 341 | dat.syn1.freq = []; 342 | for (i=2:nPts-ptsPull-1) 343 | if (dat.syn1State(i-1)==0 && dat.syn1State(i)==1) 344 | dat.syn1.v(end+1,:) = dat.v(i:i+ptsPull); 345 | dat.syn1.totC(end+1,:) = dat.totC(i:i+ptsPull); 346 | dat.syn1.pdCurrent(end+1,:) = dat.pdCurrent(i:i+ptsPull); 347 | dat.syn1.totAnIn(end+1,:) = dat.totAnIn(i:i+ptsPull); 348 | dat.syn2.freq(end+1,:) = dat.spikeFreq(i:i+ptsPull); 349 | 350 | end 351 | end 352 | 353 | %% Finds when syn2 goes from zero to ones, pulls stuff 354 | dat.syn2.v = []; 355 | dat.syn2.totC = []; 356 | dat.syn2.pdCurrent = []; 357 | dat.syn2.totAnIn = []; 358 | dat.syn2.freq = []; 359 | for (i=2:nPts-ptsPull-1) 360 | if (dat.syn2State(i-1)==0 && dat.syn2State(i)==1) 361 | dat.syn2.v(end+1,:) = dat.v(i:i+ptsPull); 362 | dat.syn2.totC(end+1,:) = dat.totC(i:i+ptsPull); 363 | dat.syn2.pdCurrent(end+1,:) = dat.pdCurrent(i:i+ptsPull); 364 | dat.syn2.totAnIn(end+1,:) = dat.totAnIn(i:i+ptsPull); 365 | dat.syn2.freq(end+1,:) = dat.spikeFreq(i:i+ptsPull); 366 | end 367 | end 368 | 369 | 370 | end 371 | 372 | function plotEvents(dat) 373 | disp('Plotting Event-Based Things') 374 | nBins = 20; % number of bins for peri-histogram 375 | %% Frequency 376 | [nCell, nPts] = size(dat.stim.v); 377 | figure('pos',[930 100 400 600]) 378 | set(gcf,'color','white') 379 | evax1 = subplot(6,1,1); 380 | tt = 1:nPts; 381 | tt = tt .*mean(dat.stim.meanDT); 382 | plot(tt,dat.stim.freq,'Color',[.5 .5 .5]); % edit TB 383 | hold on 384 | plot(tt,mean(dat.stim.freq),'k','LineWidth',2) % edit TB 385 | set(gca,'xtick',[]) 386 | set(gca,'fontsize',8) 387 | ylabel('Spike Rate (Hz)','fontsize',10) % edit TB 388 | q1 = get(evax1,'Position'); 389 | box off 390 | 391 | %% perihisto 392 | evax2 = subplot(6,1,2); 393 | histogram(dat.stim.allSpikes,nBins,'FaceColor',[.5 .5 .5],'EdgeColor','k'); 394 | 395 | set(gca,'fontsize',8) 396 | set(gca,'xtick',[]); 397 | box off 398 | ylabel('Spikes','fontsize',10) % edit TB 399 | q2 = get(evax2,'Position'); 400 | 401 | %% Raster 402 | evax3 = subplot(6,1,3); 403 | set(gca,'Visible','off') 404 | hold on 405 | for i=1:length(dat.stim.spikes) 406 | scatter(dat.stim.spikes{i},i*ones(1,length(dat.stim.spikes{i})),'.','k'); 407 | end 408 | set(gca,'xtick',[]) 409 | set(gca,'fontsize',8) 410 | ylabel('Spikes','fontsize',10) % edit TB 411 | box off 412 | q3 = get(evax3,'Position'); 413 | 414 | %% Voltage 415 | evax4 = subplot(6,1,4); 416 | plot(tt,dat.stim.v,'Color',[.5 .5 .5]) % edit TB 417 | hold on 418 | plot(tt,mean(dat.stim.v),'k','LineWidth',2) 419 | set(gca,'xtick',[]) 420 | set(gca,'fontsize',8) 421 | ylabel('Voltage (mV)','fontsize',10) % edit TB 422 | box off 423 | q4 = get(evax4,'Position'); 424 | 425 | %% Current 426 | evax5 = subplot(6,1,5); 427 | plot(tt,dat.stim.totC,'Color',[.5 .5 .5]); % edit TB 428 | hold on 429 | plot(tt,mean(dat.stim.totC),'k','LineWidth',2); % edit TB 430 | set(gca,'fontsize',8) 431 | ylabel('Current (AU)','fontsize',10) % edit TB 432 | box off 433 | xlabel('Time after stimulus (s)','fontsize',10) 434 | q5 = get(evax5,'Position'); 435 | 436 | xlim([0,dat.stim.period]) 437 | 438 | %% count histo 439 | evax6 = subplot(6,1,6); 440 | bar(0:(length(dat.stim.pCount)-1),dat.stim.pCount','FaceColor',[.5 .5 .5],'EdgeColor','k') 441 | set(gca,'fontsize',8) 442 | xlabel('Spikes per loop','fontsize',10) 443 | ylabel('Probability','fontsize',10) 444 | box off 445 | q6 = get(evax6,'Position'); 446 | 447 | 448 | 449 | %% link axes 450 | linkaxes([evax1,evax2,evax3,evax4,evax5],'x'); % link axes 451 | 452 | %% Axis Y positions 453 | q1(2) = .8; % rate 454 | q1(4) = .1; % rate height 455 | 456 | q2(2) = .7; % Hist 457 | q2(4) = .06; % Hist height 458 | 459 | q3(2) = .61; % raster 460 | q3(4) = .06; % raster height 461 | 462 | q4(2) = .4; % Voltage 463 | q4(4) = .2; % Voltage height 464 | 465 | q5(2) = .2; % current 466 | q5(4) = .15; % current height 467 | 468 | q6(2) = .1; % nSpikes 469 | q6(4) = .05; % nSpikes height 470 | 471 | 472 | 473 | set(evax1,'pos',q1) 474 | set(evax2,'pos',q2) 475 | set(evax3,'pos',q3) 476 | set(evax4,'pos',q4) 477 | set(evax5,'pos',q5) 478 | set(evax6,'pos',q6) 479 | 480 | 481 | end 482 | 483 | function dat = convertToFreqISI(dat) 484 | dat.isi = zeros(length(dat.spikeTimes)); 485 | if dat.spikesPres==1 486 | for i = 2:length(dat.isi) 487 | dat.isi(i) = dat.spikeTimes(i)-dat.spikeTimes(i-1); 488 | end 489 | dat.spikeFreq = dat.time; 490 | dat.spikeFreq = 0; 491 | for i = 2:length(dat.isi) 492 | dat.spikeFreq(dat.spikeInd(i-1):dat.spikeInd(i))=1./dat.isi(i); 493 | end 494 | dat.spikeFreq(dat.spikeInd(end):length(dat.time))=0; 495 | else 496 | dat.spikeFreq=zeros(length(dat.v)); 497 | end 498 | 499 | 500 | end 501 | 502 | 503 | -------------------------------------------------------------------------------- /MATLAB scripts/spikelingFunctions.m: -------------------------------------------------------------------------------- 1 | 2 | function spikelingFunctions(filename) 3 | %% Main spikeling function 4 | dat = loadSpikelingData(filename); % load data 5 | dat = findSpikes(dat); % find spike times 6 | dat = convertToFreqISI(dat); % compute instantaenous freq 7 | dat = checkStim(dat); % check if stimulus is present 8 | plotall(dat) % plot main function 9 | if dat.stim.stimPres==1 % if stimulus present, plot stimulus things 10 | dat = eventThings(dat); 11 | plotEvents(dat) 12 | end 13 | save spikeDat % save outputs 14 | end 15 | 16 | 17 | function dat = checkStim(dat); 18 | %% Checks if stim is present 19 | nPts = length(dat.v); 20 | nOns = 0; 21 | for i=2:nPts 22 | if (dat.stimState(i-1)==0 && dat.stimState(i)==1) 23 | nOns= 1; 24 | break 25 | end 26 | end 27 | 28 | dat.stim.stimPres = nOns; 29 | end 30 | 31 | function dat = loadSpikelingData(filename) 32 | %% Load data from csv file saved as filename 33 | 34 | datM = load(filename); % how matlab loads 35 | datMat = sortrows(datM,9); % sort (sometimes the data isn't sorted in time) 36 | % convert data from a matrix to a struct - makes things easier 37 | dat.v = datMat(1:2:end,1); 38 | dat.totC = datMat(1:2:end,2); 39 | dat.stimState = datMat(1:2:end,3); 40 | dat.syn1State = datMat(1:2:end,4); 41 | dat.syn2State = datMat(1:2:end,5); 42 | dat.pdCurrent = datMat(1:2:end,6); 43 | dat.totAnIn = datMat(1:2:end,7); 44 | dat.totSynC = datMat(1:2:end,8); 45 | dat.time = datMat(1:2:end,9)./1000./1000; %converted to seconds 46 | % every other point (spikeling is sending duplicaate values) 47 | dat.time = dat.time - dat.time(1); % set first time to zero 48 | 49 | end 50 | 51 | function plotall(dat) 52 | 53 | mx =max(dat.v); 54 | figure('pos',[100 100 800 600]) 55 | %% Plot voltage and spikes location markers 56 | set(gcf,'color','white') 57 | ax1 = subplot(4,1,2); 58 | plot(dat.time,dat.v,'k') 59 | hold on 60 | if dat.spikesPres==1 61 | scatter(dat.spikeTimes,mx*ones(1,length(dat.spikeTimes)),2,'k'); 62 | end 63 | set(gca,'fontsize',8) 64 | ylabel('Voltage (mV)','fontsize',10) % edit TB 65 | box off 66 | set(gca,'xtick',[]) 67 | 68 | p1 = get(ax1,'Position'); 69 | %% Plot currents 70 | ax2 = subplot(4,1,3); 71 | plot(dat.time,dat.totC,'k') 72 | box off 73 | set(gca,'xtick',[]) 74 | hold on 75 | plot(dat.time,dat.pdCurrent,'Color',[.25 .25 .25]) 76 | plot(dat.time,dat.totAnIn,'Color',[.5 .5 .5]) 77 | set(gca,'fontsize',8) 78 | ylabel('Currents (AU)','fontsize',10) % edit TB 79 | legend('Total Current','Photodiode Current','Total Analog Input') 80 | p2 = get(ax2,'Position'); 81 | %% Plot frequencies 82 | ax3 = subplot(4,1,1); 83 | p3 = get(ax3,'Position'); 84 | plot(dat.time,dat.spikeFreq,'k') 85 | set(gca,'fontsize',8) 86 | ylabel('Spike Rate (Hz)','fontsize',10) % edit TB 87 | box off 88 | set(gca,'xtick',[]) 89 | 90 | %% Plot synapse and stimulus states 91 | ax4 = subplot(4,1,4); 92 | plot(dat.time,dat.syn1State,'Color',[.5 .5 .5]) 93 | hold on 94 | plot(dat.time,dat.syn2State,'Color',[.25 .25 .25]) 95 | box off 96 | ylim([-0.1,1.1]) 97 | plot(dat.time,dat.stimState,'k') 98 | set(gca,'fontsize',8) 99 | ylabel('Inputs','fontsize',10) 100 | xlabel('Time (s)','fontsize',10) % edit TB 101 | 102 | linkaxes([ax1,ax2,ax3,ax4],'x'); % link axes 103 | % so changing x on one changes all 104 | xlim([0,max(dat.time)]) 105 | 106 | legend('Synapse 1','Synapse 2','Stimulus State') 107 | p4 = get(ax4,'Position'); 108 | 109 | %% Axis Y positions 110 | p3(2) = .8; % rate 111 | p3(4) = .1; % rate height 112 | p1(2) = 0.45; % voltage 113 | p1(4) = .3; % voltage height 114 | p2(2) = 0.2; % currents 115 | p2(4) = .2; % currents height 116 | p4(2) = .1; % stim 117 | p4(4) = .05; % stim height 118 | set(ax1,'pos',p1) 119 | set(ax2,'pos',p2) 120 | set(ax3,'pos',p3) 121 | set(ax4,'pos',p4) 122 | 123 | end 124 | 125 | function dat = findSpikes(dat) 126 | %% Finds spikes 127 | spikeTime = []; % initialize empty vector of spike times (we don't 128 | % know how many spikes a priori 129 | spikeInd = []; % initialize indice vector 130 | thresh = 10; % must be above this value to be considered a spike 131 | nPts = length(dat.time); 132 | tempTrain = zeros(1,nPts); % initialize a spike train as no zeros 133 | for i=1:nPts-1 % loop over points in times 134 | if (dat.v(i) >= thresh && dat.v(i+1) 0 147 | dat.spikesPres = 1; 148 | else 149 | dat.spikesPres = 0; 150 | end 151 | 152 | end 153 | 154 | function dat = eventThings(dat) 155 | %% Finds the points when the stimuli goes from 0 to 1 and pulls stuff 156 | nPts = length(dat.stimState); 157 | dat.stim.v = []; 158 | dat.stim.totC = []; 159 | dat.stim.pdCurrent = []; 160 | dat.stim.totAnIn = []; 161 | dat.stim.meanDT = []; 162 | dat.stim.freq = []; 163 | dat.stim.startInd = []; 164 | dat.stim.spikes = {}; 165 | dat.stim.periCount = []; 166 | for i=2:nPts 167 | if (dat.stimState(i-1)==0 && dat.stimState(i)==1) 168 | dat.stim.startInd(end+1) = i; 169 | end 170 | end 171 | for (i=2:length(dat.stim.startInd)) 172 | interval(i-1) = dat.stim.startInd(i)-dat.stim.startInd(i-1); 173 | end 174 | ptsPull = ceil(mean(interval)); 175 | dat.stim.period = dat.time(ptsPull)-dat.time(1); 176 | 177 | for (i=2:nPts-ptsPull-1) 178 | if (dat.stimState(i-1)==0 && dat.stimState(i)==1) 179 | dat.stim.v(end+1,:) = dat.v(i:i+ptsPull); 180 | dat.stim.totC(end+1,:) = dat.totC(i:i+ptsPull); 181 | dat.stim.pdCurrent(end+1,:) = dat.pdCurrent(i:i+ptsPull); 182 | dat.stim.totAnIn(end+1,:) = dat.totAnIn(i:i+ptsPull); 183 | dat.stim.meanDT(end+1) = (dat.time(i+ptsPull)-dat.time(i))/ptsPull; 184 | dat.stim.freq(end+1,:) = dat.spikeFreq(i:i+ptsPull); 185 | dat.stim.spikes{end+1}(:) = dat.spikeTimes(find(dat.spikeTimes > dat.time(i) & dat.spikeTimes < dat.time(i+ptsPull))); 186 | dat.stim.spikes{end}= dat.stim.spikes{end} - dat.time(i); 187 | dat.stim.periCount(end+1) = length(dat.stim.spikes{end}); 188 | end 189 | end 190 | periCountMax = max(dat.stim.periCount); 191 | for i=1:periCountMax+1 192 | dat.stim.pCount(i) = length(find(dat.stim.periCount==(i-1)))/length(dat.stim.periCount); 193 | end 194 | 195 | dat.stim.allSpikes = cell2mat(dat.stim.spikes) ; 196 | 197 | 198 | 199 | 200 | %% Finds when syn1 goes from zero to ones, pulls stuff 201 | dat.syn1.v = []; 202 | dat.syn1.totC = []; 203 | dat.syn1.pdCurrent = []; 204 | dat.syn1.totAnIn = []; 205 | dat.syn1.freq = []; 206 | for (i=2:nPts-ptsPull-1) 207 | if (dat.syn1State(i-1)==0 && dat.syn1State(i)==1) 208 | dat.syn1.v(end+1,:) = dat.v(i:i+ptsPull); 209 | dat.syn1.totC(end+1,:) = dat.totC(i:i+ptsPull); 210 | dat.syn1.pdCurrent(end+1,:) = dat.pdCurrent(i:i+ptsPull); 211 | dat.syn1.totAnIn(end+1,:) = dat.totAnIn(i:i+ptsPull); 212 | dat.syn2.freq(end+1,:) = dat.spikeFreq(i:i+ptsPull); 213 | 214 | end 215 | end 216 | 217 | %% Finds when syn2 goes from zero to ones, pulls stuff 218 | dat.syn2.v = []; 219 | dat.syn2.totC = []; 220 | dat.syn2.pdCurrent = []; 221 | dat.syn2.totAnIn = []; 222 | dat.syn2.freq = []; 223 | for (i=2:nPts-ptsPull-1) 224 | if (dat.syn2State(i-1)==0 && dat.syn2State(i)==1) 225 | dat.syn2.v(end+1,:) = dat.v(i:i+ptsPull); 226 | dat.syn2.totC(end+1,:) = dat.totC(i:i+ptsPull); 227 | dat.syn2.pdCurrent(end+1,:) = dat.pdCurrent(i:i+ptsPull); 228 | dat.syn2.totAnIn(end+1,:) = dat.totAnIn(i:i+ptsPull); 229 | dat.syn2.freq(end+1,:) = dat.spikeFreq(i:i+ptsPull); 230 | end 231 | end 232 | 233 | 234 | end 235 | 236 | function plotEvents(dat) 237 | nBins = 20; % number of bins for peri-histogram 238 | %% Frequency 239 | [nCell, nPts] = size(dat.stim.v); 240 | figure('pos',[930 100 400 600]) 241 | set(gcf,'color','white') 242 | evax1 = subplot(6,1,1); 243 | tt = 1:nPts; 244 | tt = tt .*mean(dat.stim.meanDT); 245 | plot(tt,dat.stim.freq,'Color',[.5 .5 .5]); % edit TB 246 | hold on 247 | plot(tt,mean(dat.stim.freq),'k','LineWidth',2) % edit TB 248 | set(gca,'xtick',[]) 249 | set(gca,'fontsize',8) 250 | ylabel('Spike Rate (Hz)','fontsize',10) % edit TB 251 | q1 = get(evax1,'Position'); 252 | box off 253 | 254 | %% perihisto 255 | evax2 = subplot(6,1,2); 256 | histogram(dat.stim.allSpikes,nBins,'FaceColor',[.5 .5 .5],'EdgeColor','k'); 257 | 258 | set(gca,'fontsize',8) 259 | set(gca,'xtick',[]); 260 | box off 261 | ylabel('Spikes','fontsize',10) % edit TB 262 | q2 = get(evax2,'Position'); 263 | 264 | %% Raster 265 | evax3 = subplot(6,1,3); 266 | set(gca,'Visible','off') 267 | hold on 268 | for i=1:length(dat.stim.spikes) 269 | scatter(dat.stim.spikes{i},i*ones(1,length(dat.stim.spikes{i})),'.','k'); 270 | end 271 | set(gca,'xtick',[]) 272 | set(gca,'fontsize',8) 273 | ylabel('Spikes','fontsize',10) % edit TB 274 | box off 275 | q3 = get(evax3,'Position'); 276 | 277 | %% Voltage 278 | evax4 = subplot(6,1,4); 279 | plot(tt,dat.stim.v,'Color',[.5 .5 .5]) % edit TB 280 | hold on 281 | plot(tt,mean(dat.stim.v),'k','LineWidth',2) 282 | set(gca,'xtick',[]) 283 | set(gca,'fontsize',8) 284 | ylabel('Voltage (mV)','fontsize',10) % edit TB 285 | box off 286 | q4 = get(evax4,'Position'); 287 | 288 | %% Current 289 | evax5 = subplot(6,1,5); 290 | plot(tt,dat.stim.totC,'Color',[.5 .5 .5]); % edit TB 291 | hold on 292 | plot(tt,mean(dat.stim.totC),'k','LineWidth',2); % edit TB 293 | set(gca,'fontsize',8) 294 | ylabel('Current (AU)','fontsize',10) % edit TB 295 | box off 296 | xlabel('Time after stimulus (s)','fontsize',10) 297 | q5 = get(evax5,'Position'); 298 | 299 | xlim([0,dat.stim.period]) 300 | 301 | %% count histo 302 | evax6 = subplot(6,1,6); 303 | bar(0:(length(dat.stim.pCount)-1),dat.stim.pCount','FaceColor',[.5 .5 .5],'EdgeColor','k') 304 | set(gca,'fontsize',8) 305 | xlabel('Spikes per loop','fontsize',10) 306 | ylabel('Probability','fontsize',10) 307 | box off 308 | q6 = get(evax6,'Position'); 309 | 310 | 311 | 312 | %% link axes 313 | linkaxes([evax1,evax2,evax3,evax4,evax5],'x'); % link axes 314 | 315 | %% Axis Y positions 316 | q1(2) = .8; % rate 317 | q1(4) = .1; % rate height 318 | 319 | q2(2) = .7; % Hist 320 | q2(4) = .06; % Hist height 321 | 322 | q3(2) = .61; % raster 323 | q3(4) = .06; % raster height 324 | 325 | q4(2) = .4; % Voltage 326 | q4(4) = .2; % Voltage height 327 | 328 | q5(2) = .2; % current 329 | q5(4) = .15; % current height 330 | 331 | q6(2) = .1; % nSpikes 332 | q6(4) = .05; % nSpikes height 333 | 334 | 335 | 336 | set(evax1,'pos',q1) 337 | set(evax2,'pos',q2) 338 | set(evax3,'pos',q3) 339 | set(evax4,'pos',q4) 340 | set(evax5,'pos',q5) 341 | set(evax6,'pos',q6) 342 | 343 | 344 | end 345 | 346 | function dat = convertToFreqISI(dat) 347 | dat.isi = zeros(length(dat.spikeTimes)); 348 | if dat.spikesPres==1 349 | for i = 2:length(dat.isi) 350 | dat.isi(i) = dat.spikeTimes(i)-dat.spikeTimes(i-1); 351 | end 352 | dat.spikeFreq = dat.time; 353 | dat.spikeFreq = 0; 354 | for i = 2:length(dat.isi) 355 | dat.spikeFreq(dat.spikeInd(i-1):dat.spikeInd(i))=1./dat.isi(i); 356 | end 357 | dat.spikeFreq(dat.spikeInd(end):length(dat.time))=0; 358 | else 359 | dat.spikeFreq=zeros(length(dat.v)); 360 | end 361 | 362 | 363 | end 364 | 365 | 366 | -------------------------------------------------------------------------------- /PCB/Spikeling PCB.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/PCB/Spikeling PCB.pdf -------------------------------------------------------------------------------- /PCB/Spikeling PCB.pro: -------------------------------------------------------------------------------- 1 | EAGLE AutoRouter Statistics: 2 | 3 | Job : C:/Dropbox/3d PRINTS/Own Designs/ArduinoNeuron/spikeling schematic6.brd 4 | 5 | Start at : 14:47:39 (13/09/2017) 6 | End at : 14:48:00 (13/09/2017) 7 | Elapsed time : 00:00:19 8 | 9 | Signals : 17 RoutingGrid: 7.03543 mil Layers: 2 10 | Connections : 55 predefined: 0 ( 0 Vias ) 11 | 12 | Router memory : 1334032 13 | 14 | Passname : TopRouter Route Optimize1 Optimize2 Optimize3 Optimize4 Optimize5 Optimize6 Optimize7 Optimize8 15 | 16 | Time per pass : 00:00:09 00:00:01 00:00:01 00:00:01 00:00:01 00:00:01 00:00:02 00:00:01 00:00:01 00:00:01 17 | Number of Ripups : 0 0 0 0 0 0 0 0 0 0 18 | max. Level : 0 0 0 0 0 0 0 0 0 0 19 | max. Total : 0 0 0 0 0 0 0 0 0 0 20 | 21 | Routed : 24 55 55 55 55 55 55 55 55 55 22 | Vias : 0 0 0 0 0 0 0 0 0 0 23 | Resolution : 43.6 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 100.0 % 24 | 25 | Final : 100.0% finished 26 | -------------------------------------------------------------------------------- /PCB/gerber.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/PCB/gerber.zip -------------------------------------------------------------------------------- /PCB/gerbers/B.Cu.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | %ADD10C,3.160000*% 10 | %ADD11C,4.950000*% 11 | %ADD12P,1.814519X8X112.500000*% 12 | %ADD13P,1.429621X8X112.500000*% 13 | %ADD14P,1.429621X8X292.500000*% 14 | %ADD15C,1.308000*% 15 | %ADD16C,1.308000*% 16 | %ADD17C,1.943100*% 17 | %ADD18C,1.676400*% 18 | %ADD19R,2.800000X2.800000*% 19 | %ADD20P,2.336880X8X22.500000*% 20 | %ADD21C,0.152400*% 21 | 22 | 23 | D10* 24 | X474750Y771550D03* 25 | X347750Y771550D03* 26 | D11* 27 | X530400Y619150D03* 28 | X292100Y619150D03* 29 | X530400Y396850D03* 30 | X292100Y396850D03* 31 | D12* 32 | X774700Y88900D03* 33 | X774700Y114300D03* 34 | D13* 35 | X393700Y63500D03* 36 | X393700Y165100D03* 37 | D14* 38 | X444500Y165100D03* 39 | X444500Y63500D03* 40 | X495300Y165100D03* 41 | X495300Y63500D03* 42 | X546100Y165100D03* 43 | X546100Y63500D03* 44 | D15* 45 | X768160Y406400D02* 46 | X781240Y406400D01* 47 | X781240Y431800D02* 48 | X768160Y431800D01* 49 | X768160Y457200D02* 50 | X781240Y457200D01* 51 | X781240Y482600D02* 52 | X768160Y482600D01* 53 | X768160Y508000D02* 54 | X781240Y508000D01* 55 | X781240Y533400D02* 56 | X768160Y533400D01* 57 | X768160Y558800D02* 58 | X781240Y558800D01* 59 | X781240Y584200D02* 60 | X768160Y584200D01* 61 | X768160Y609600D02* 62 | X781240Y609600D01* 63 | X781240Y635000D02* 64 | X768160Y635000D01* 65 | X768160Y660400D02* 66 | X781240Y660400D01* 67 | X781240Y685800D02* 68 | X768160Y685800D01* 69 | X628840Y406400D02* 70 | X615760Y406400D01* 71 | X615760Y431800D02* 72 | X628840Y431800D01* 73 | X628840Y457200D02* 74 | X615760Y457200D01* 75 | X615760Y609600D02* 76 | X628840Y609600D01* 77 | X628840Y635000D02* 78 | X615760Y635000D01* 79 | X615760Y660400D02* 80 | X628840Y660400D01* 81 | X628840Y685800D02* 82 | X615760Y685800D01* 83 | X615760Y762000D02* 84 | X628840Y762000D01* 85 | X768160Y762000D02* 86 | X781240Y762000D01* 87 | X781240Y736600D02* 88 | X768160Y736600D01* 89 | X768160Y711200D02* 90 | X781240Y711200D01* 91 | X628840Y736600D02* 92 | X615760Y736600D01* 93 | X615760Y711200D02* 94 | X628840Y711200D01* 95 | X628840Y482600D02* 96 | X615760Y482600D01* 97 | D16* 98 | X673100Y419100D03* 99 | X698500Y419100D03* 100 | X723900Y419100D03* 101 | D15* 102 | X628840Y584200D02* 103 | X615760Y584200D01* 104 | X615760Y558800D02* 105 | X628840Y558800D01* 106 | X628840Y533400D02* 107 | X615760Y533400D01* 108 | X615760Y508000D02* 109 | X628840Y508000D01* 110 | D16* 111 | X673100Y393700D03* 112 | X698500Y393700D03* 113 | X723900Y393700D03* 114 | D17* 115 | X914400Y711200D03* 116 | X965200Y762000D03* 117 | X863600Y762000D03* 118 | X863600Y660400D03* 119 | X965200Y660400D03* 120 | X914400Y558800D03* 121 | X965200Y609600D03* 122 | X863600Y609600D03* 123 | X863600Y508000D03* 124 | X965200Y508000D03* 125 | X914400Y254000D03* 126 | X965200Y304800D03* 127 | X863600Y304800D03* 128 | X863600Y203200D03* 129 | X965200Y203200D03* 130 | X914400Y101600D03* 131 | X965200Y152400D03* 132 | X863600Y152400D03* 133 | X863600Y50800D03* 134 | X965200Y50800D03* 135 | X914400Y406400D03* 136 | X965200Y457200D03* 137 | X863600Y457200D03* 138 | X863600Y355600D03* 139 | X965200Y355600D03* 140 | D18* 141 | X209700Y267100D03* 142 | X209700Y292100D03* 143 | X209700Y317100D03* 144 | D19* 145 | X139700Y337100D03* 146 | X139700Y247100D03* 147 | D18* 148 | X209700Y686200D03* 149 | X209700Y711200D03* 150 | X209700Y736200D03* 151 | D19* 152 | X139700Y756200D03* 153 | X139700Y666200D03* 154 | D18* 155 | X209700Y546500D03* 156 | X209700Y571500D03* 157 | X209700Y596500D03* 158 | D19* 159 | X139700Y616500D03* 160 | X139700Y526500D03* 161 | D18* 162 | X209700Y406800D03* 163 | X209700Y431800D03* 164 | X209700Y456800D03* 165 | D19* 166 | X139700Y476800D03* 167 | X139700Y386800D03* 168 | D20* 169 | X647700Y254000D03* 170 | X749300Y254000D03* 171 | X317500Y139700D03* 172 | X317500Y88900D03* 173 | X596900Y139700D03* 174 | X596900Y88900D03* 175 | X139700Y127000D03* 176 | X139700Y101600D03* 177 | X266700Y88900D03* 178 | X266700Y139700D03* 179 | D21* 180 | X773771Y730883D02* 181 | X773771Y736244D01* 182 | X773771Y730883D02* 183 | X643320Y600432D01* 184 | X643320Y312725D01* 185 | X496786Y166191D01* 186 | X773771Y736244D02* 187 | X774700Y736600D01* 188 | X496786Y166191D02* 189 | X495300Y165100D01* 190 | X611154Y101859D02* 191 | X913157Y101859D01* 192 | X611154Y101859D02* 193 | X598645Y89350D01* 194 | X913157Y101859D02* 195 | X914400Y101600D01* 196 | X598645Y89350D02* 197 | X596900Y88900D01* 198 | X210866Y457472D02* 199 | X210866Y530739D01* 200 | X221588Y541461D01* 201 | X221588Y584349D01* 202 | X210866Y595071D01* 203 | X210866Y457472D02* 204 | X209700Y456800D01* 205 | X210866Y595071D02* 206 | X209700Y596500D01* 207 | X210866Y727309D02* 208 | X210866Y734457D01* 209 | X210866Y727309D02* 210 | X221588Y716587D01* 211 | X221588Y607580D01* 212 | X210866Y596858D01* 213 | X210866Y734457D02* 214 | X209700Y736200D01* 215 | X210866Y596858D02* 216 | X209700Y596500D01* 217 | X275198Y770197D02* 218 | X346678Y770197D01* 219 | X275198Y770197D02* 220 | X221588Y716587D01* 221 | X346678Y770197D02* 222 | X347750Y771550D01* 223 | X141173Y216227D02* 224 | X141173Y128664D01* 225 | X141173Y216227D02* 226 | X198357Y273411D01* 227 | X198357Y305577D01* 228 | X209079Y316299D01* 229 | X141173Y128664D02* 230 | X139700Y127000D01* 231 | X209079Y316299D02* 232 | X209700Y317100D01* 233 | X210866Y446750D02* 234 | X210866Y455685D01* 235 | X210866Y446750D02* 236 | X221588Y436028D01* 237 | X221588Y328808D01* 238 | X210866Y318086D01* 239 | X210866Y455685D02* 240 | X209700Y456800D01* 241 | X210866Y318086D02* 242 | X209700Y317100D01* 243 | X394927Y64332D02* 244 | X430667Y64332D01* 245 | X439602Y73267D01* 246 | X536100Y73267D01* 247 | X545035Y64332D01* 248 | X394927Y64332D02* 249 | X393700Y63500D01* 250 | X545035Y64332D02* 251 | X546100Y63500D01* 252 | X596858Y134025D02* 253 | X596858Y139386D01* 254 | X596858Y134025D02* 255 | X536100Y73267D01* 256 | X596858Y139386D02* 257 | X596900Y139700D01* 258 | X863121Y509295D02* 259 | X863121Y609367D01* 260 | X863600Y609600D01* 261 | X863121Y509295D02* 262 | X863600Y508000D01* 263 | X863121Y303790D02* 264 | X863121Y203718D01* 265 | X863121Y303790D02* 266 | X863600Y304800D01* 267 | X863121Y203718D02* 268 | X863600Y203200D01* 269 | X863121Y355613D02* 270 | X863121Y455685D01* 271 | X863600Y457200D01* 272 | X863121Y355613D02* 273 | X863600Y355600D01* 274 | X259115Y126877D02* 275 | X141173Y126877D01* 276 | X259115Y126877D02* 277 | X321660Y64332D01* 278 | X393140Y64332D01* 279 | X141173Y126877D02* 280 | X139700Y127000D01* 281 | X393140Y64332D02* 282 | X393700Y63500D01* 283 | X773771Y680847D02* 284 | X773771Y684421D01* 285 | X773771Y680847D02* 286 | X646894Y553970D01* 287 | X646894Y302003D01* 288 | X500360Y155469D01* 289 | X453898Y155469D01* 290 | X444963Y164404D01* 291 | X773771Y684421D02* 292 | X774700Y685800D01* 293 | X444500Y165100D02* 294 | X444963Y164404D01* 295 | X773771Y502147D02* 296 | X773771Y507508D01* 297 | X773771Y502147D02* 298 | X709439Y437815D01* 299 | X709439Y335956D01* 300 | X546822Y173339D01* 301 | X546822Y166191D01* 302 | X773771Y507508D02* 303 | X774700Y508000D01* 304 | X546822Y166191D02* 305 | X546100Y165100D01* 306 | X775558Y559331D02* 307 | X780919Y559331D01* 308 | X913157Y691569D01* 309 | X913157Y709439D01* 310 | X775558Y559331D02* 311 | X774700Y558800D01* 312 | X913157Y709439D02* 313 | X914400Y711200D01* 314 | X775558Y532526D02* 315 | X775558Y527165D01* 316 | X791641Y511082D01* 317 | X791641Y296642D01* 318 | X750540Y255541D01* 319 | X775558Y532526D02* 320 | X774700Y533400D01* 321 | X750540Y255541D02* 322 | X749300Y254000D01* 323 | X621876Y407436D02* 324 | X621876Y411010D01* 325 | X475342Y557544D01* 326 | X475342Y770197D01* 327 | X621876Y407436D02* 328 | X622300Y406400D01* 329 | X475342Y770197D02* 330 | X474750Y771550D01* 331 | X623663Y609367D02* 332 | X623663Y604006D01* 333 | X639746Y587923D01* 334 | X639746Y403862D01* 335 | X528952Y293068D01* 336 | X210866Y293068D01* 337 | X622300Y609600D02* 338 | X623663Y609367D01* 339 | X210866Y293068D02* 340 | X209700Y292100D01* 341 | M02* 342 | -------------------------------------------------------------------------------- /PCB/gerbers/B.Mask.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | %ADD10C,3.363200*% 10 | %ADD11C,5.153200*% 11 | %ADD12P,2.034460X8X112.500000*% 12 | %ADD13P,1.649562X8X112.500000*% 13 | %ADD14P,1.649562X8X292.500000*% 14 | %ADD15C,1.511200*% 15 | %ADD16C,1.511200*% 16 | %ADD17C,2.146300*% 17 | %ADD18C,1.879600*% 18 | %ADD19R,3.003200X3.003200*% 19 | %ADD20P,2.556822X8X22.500000*% 20 | 21 | 22 | D10* 23 | X474750Y771550D03* 24 | X347750Y771550D03* 25 | D11* 26 | X530400Y619150D03* 27 | X292100Y619150D03* 28 | X530400Y396850D03* 29 | X292100Y396850D03* 30 | D12* 31 | X774700Y88900D03* 32 | X774700Y114300D03* 33 | D13* 34 | X393700Y63500D03* 35 | X393700Y165100D03* 36 | D14* 37 | X444500Y165100D03* 38 | X444500Y63500D03* 39 | X495300Y165100D03* 40 | X495300Y63500D03* 41 | X546100Y165100D03* 42 | X546100Y63500D03* 43 | D15* 44 | X768160Y406400D02* 45 | X781240Y406400D01* 46 | X781240Y431800D02* 47 | X768160Y431800D01* 48 | X768160Y457200D02* 49 | X781240Y457200D01* 50 | X781240Y482600D02* 51 | X768160Y482600D01* 52 | X768160Y508000D02* 53 | X781240Y508000D01* 54 | X781240Y533400D02* 55 | X768160Y533400D01* 56 | X768160Y558800D02* 57 | X781240Y558800D01* 58 | X781240Y584200D02* 59 | X768160Y584200D01* 60 | X768160Y609600D02* 61 | X781240Y609600D01* 62 | X781240Y635000D02* 63 | X768160Y635000D01* 64 | X768160Y660400D02* 65 | X781240Y660400D01* 66 | X781240Y685800D02* 67 | X768160Y685800D01* 68 | X628840Y406400D02* 69 | X615760Y406400D01* 70 | X615760Y431800D02* 71 | X628840Y431800D01* 72 | X628840Y457200D02* 73 | X615760Y457200D01* 74 | X615760Y609600D02* 75 | X628840Y609600D01* 76 | X628840Y635000D02* 77 | X615760Y635000D01* 78 | X615760Y660400D02* 79 | X628840Y660400D01* 80 | X628840Y685800D02* 81 | X615760Y685800D01* 82 | X615760Y762000D02* 83 | X628840Y762000D01* 84 | X768160Y762000D02* 85 | X781240Y762000D01* 86 | X781240Y736600D02* 87 | X768160Y736600D01* 88 | X768160Y711200D02* 89 | X781240Y711200D01* 90 | X628840Y736600D02* 91 | X615760Y736600D01* 92 | X615760Y711200D02* 93 | X628840Y711200D01* 94 | X628840Y482600D02* 95 | X615760Y482600D01* 96 | D16* 97 | X673100Y419100D03* 98 | X698500Y419100D03* 99 | X723900Y419100D03* 100 | D15* 101 | X628840Y584200D02* 102 | X615760Y584200D01* 103 | X615760Y558800D02* 104 | X628840Y558800D01* 105 | X628840Y533400D02* 106 | X615760Y533400D01* 107 | X615760Y508000D02* 108 | X628840Y508000D01* 109 | D16* 110 | X673100Y393700D03* 111 | X698500Y393700D03* 112 | X723900Y393700D03* 113 | D17* 114 | X914400Y711200D03* 115 | X965200Y762000D03* 116 | X863600Y762000D03* 117 | X863600Y660400D03* 118 | X965200Y660400D03* 119 | X914400Y558800D03* 120 | X965200Y609600D03* 121 | X863600Y609600D03* 122 | X863600Y508000D03* 123 | X965200Y508000D03* 124 | X914400Y254000D03* 125 | X965200Y304800D03* 126 | X863600Y304800D03* 127 | X863600Y203200D03* 128 | X965200Y203200D03* 129 | X914400Y101600D03* 130 | X965200Y152400D03* 131 | X863600Y152400D03* 132 | X863600Y50800D03* 133 | X965200Y50800D03* 134 | X914400Y406400D03* 135 | X965200Y457200D03* 136 | X863600Y457200D03* 137 | X863600Y355600D03* 138 | X965200Y355600D03* 139 | D18* 140 | X209700Y267100D03* 141 | X209700Y292100D03* 142 | X209700Y317100D03* 143 | D19* 144 | X139700Y337100D03* 145 | X139700Y247100D03* 146 | D18* 147 | X209700Y686200D03* 148 | X209700Y711200D03* 149 | X209700Y736200D03* 150 | D19* 151 | X139700Y756200D03* 152 | X139700Y666200D03* 153 | D18* 154 | X209700Y546500D03* 155 | X209700Y571500D03* 156 | X209700Y596500D03* 157 | D19* 158 | X139700Y616500D03* 159 | X139700Y526500D03* 160 | D18* 161 | X209700Y406800D03* 162 | X209700Y431800D03* 163 | X209700Y456800D03* 164 | D19* 165 | X139700Y476800D03* 166 | X139700Y386800D03* 167 | D20* 168 | X647700Y254000D03* 169 | X749300Y254000D03* 170 | X317500Y139700D03* 171 | X317500Y88900D03* 172 | X596900Y139700D03* 173 | X596900Y88900D03* 174 | X139700Y127000D03* 175 | X139700Y101600D03* 176 | X266700Y88900D03* 177 | X266700Y139700D03* 178 | M02* 179 | -------------------------------------------------------------------------------- /PCB/gerbers/B.Paste.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | 10 | 11 | M02* 12 | -------------------------------------------------------------------------------- /PCB/gerbers/B.SilkS.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | 10 | 11 | M02* 12 | -------------------------------------------------------------------------------- /PCB/gerbers/F.Cu.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | %ADD10C,3.160000*% 10 | %ADD11C,4.950000*% 11 | %ADD12P,1.814519X8X112.500000*% 12 | %ADD13P,1.429621X8X112.500000*% 13 | %ADD14P,1.429621X8X292.500000*% 14 | %ADD15C,1.308000*% 15 | %ADD16C,1.308000*% 16 | %ADD17C,1.943100*% 17 | %ADD18C,1.676400*% 18 | %ADD19R,2.800000X2.800000*% 19 | %ADD20P,2.336880X8X22.500000*% 20 | %ADD21C,0.152400*% 21 | 22 | 23 | D10* 24 | X474750Y771550D03* 25 | X347750Y771550D03* 26 | D11* 27 | X530400Y619150D03* 28 | X292100Y619150D03* 29 | X530400Y396850D03* 30 | X292100Y396850D03* 31 | D12* 32 | X774700Y88900D03* 33 | X774700Y114300D03* 34 | D13* 35 | X393700Y63500D03* 36 | X393700Y165100D03* 37 | D14* 38 | X444500Y165100D03* 39 | X444500Y63500D03* 40 | X495300Y165100D03* 41 | X495300Y63500D03* 42 | X546100Y165100D03* 43 | X546100Y63500D03* 44 | D15* 45 | X768160Y406400D02* 46 | X781240Y406400D01* 47 | X781240Y431800D02* 48 | X768160Y431800D01* 49 | X768160Y457200D02* 50 | X781240Y457200D01* 51 | X781240Y482600D02* 52 | X768160Y482600D01* 53 | X768160Y508000D02* 54 | X781240Y508000D01* 55 | X781240Y533400D02* 56 | X768160Y533400D01* 57 | X768160Y558800D02* 58 | X781240Y558800D01* 59 | X781240Y584200D02* 60 | X768160Y584200D01* 61 | X768160Y609600D02* 62 | X781240Y609600D01* 63 | X781240Y635000D02* 64 | X768160Y635000D01* 65 | X768160Y660400D02* 66 | X781240Y660400D01* 67 | X781240Y685800D02* 68 | X768160Y685800D01* 69 | X628840Y406400D02* 70 | X615760Y406400D01* 71 | X615760Y431800D02* 72 | X628840Y431800D01* 73 | X628840Y457200D02* 74 | X615760Y457200D01* 75 | X615760Y609600D02* 76 | X628840Y609600D01* 77 | X628840Y635000D02* 78 | X615760Y635000D01* 79 | X615760Y660400D02* 80 | X628840Y660400D01* 81 | X628840Y685800D02* 82 | X615760Y685800D01* 83 | X615760Y762000D02* 84 | X628840Y762000D01* 85 | X768160Y762000D02* 86 | X781240Y762000D01* 87 | X781240Y736600D02* 88 | X768160Y736600D01* 89 | X768160Y711200D02* 90 | X781240Y711200D01* 91 | X628840Y736600D02* 92 | X615760Y736600D01* 93 | X615760Y711200D02* 94 | X628840Y711200D01* 95 | X628840Y482600D02* 96 | X615760Y482600D01* 97 | D16* 98 | X673100Y419100D03* 99 | X698500Y419100D03* 100 | X723900Y419100D03* 101 | D15* 102 | X628840Y584200D02* 103 | X615760Y584200D01* 104 | X615760Y558800D02* 105 | X628840Y558800D01* 106 | X628840Y533400D02* 107 | X615760Y533400D01* 108 | X615760Y508000D02* 109 | X628840Y508000D01* 110 | D16* 111 | X673100Y393700D03* 112 | X698500Y393700D03* 113 | X723900Y393700D03* 114 | D17* 115 | X914400Y711200D03* 116 | X965200Y762000D03* 117 | X863600Y762000D03* 118 | X863600Y660400D03* 119 | X965200Y660400D03* 120 | X914400Y558800D03* 121 | X965200Y609600D03* 122 | X863600Y609600D03* 123 | X863600Y508000D03* 124 | X965200Y508000D03* 125 | X914400Y254000D03* 126 | X965200Y304800D03* 127 | X863600Y304800D03* 128 | X863600Y203200D03* 129 | X965200Y203200D03* 130 | X914400Y101600D03* 131 | X965200Y152400D03* 132 | X863600Y152400D03* 133 | X863600Y50800D03* 134 | X965200Y50800D03* 135 | X914400Y406400D03* 136 | X965200Y457200D03* 137 | X863600Y457200D03* 138 | X863600Y355600D03* 139 | X965200Y355600D03* 140 | D18* 141 | X209700Y267100D03* 142 | X209700Y292100D03* 143 | X209700Y317100D03* 144 | D19* 145 | X139700Y337100D03* 146 | X139700Y247100D03* 147 | D18* 148 | X209700Y686200D03* 149 | X209700Y711200D03* 150 | X209700Y736200D03* 151 | D19* 152 | X139700Y756200D03* 153 | X139700Y666200D03* 154 | D18* 155 | X209700Y546500D03* 156 | X209700Y571500D03* 157 | X209700Y596500D03* 158 | D19* 159 | X139700Y616500D03* 160 | X139700Y526500D03* 161 | D18* 162 | X209700Y406800D03* 163 | X209700Y431800D03* 164 | X209700Y456800D03* 165 | D19* 166 | X139700Y476800D03* 167 | X139700Y386800D03* 168 | D20* 169 | X647700Y254000D03* 170 | X749300Y254000D03* 171 | X317500Y139700D03* 172 | X317500Y88900D03* 173 | X596900Y139700D03* 174 | X596900Y88900D03* 175 | X139700Y127000D03* 176 | X139700Y101600D03* 177 | X266700Y88900D03* 178 | X266700Y139700D03* 179 | D21* 180 | X496786Y64332D02* 181 | X532526Y64332D01* 182 | X555757Y87563D01* 183 | X596858Y87563D01* 184 | X496786Y64332D02* 185 | X495300Y63500D01* 186 | X596858Y87563D02* 187 | X596900Y88900D01* 188 | X621876Y430667D02* 189 | X366335Y430667D01* 190 | X253754Y318086D01* 191 | X210866Y318086D01* 192 | X621876Y430667D02* 193 | X622300Y431800D01* 194 | X210866Y318086D02* 195 | X209700Y317100D01* 196 | X646894Y253754D02* 197 | X646894Y189422D01* 198 | X598645Y141173D01* 199 | X646894Y253754D02* 200 | X647700Y254000D01* 201 | X598645Y141173D02* 202 | X596900Y139700D01* 203 | X864908Y763049D02* 204 | X964980Y763049D01* 205 | X864908Y763049D02* 206 | X863600Y762000D01* 207 | X964980Y763049D02* 208 | X965200Y762000D01* 209 | X964980Y659403D02* 210 | X964980Y611154D01* 211 | X965200Y609600D01* 212 | X964980Y659403D02* 213 | X965200Y660400D01* 214 | X863121Y659403D02* 215 | X863121Y611154D01* 216 | X863600Y609600D01* 217 | X863121Y659403D02* 218 | X863600Y660400D01* 219 | X863121Y507508D02* 220 | X863121Y457472D01* 221 | X863600Y457200D01* 222 | X863121Y507508D02* 223 | X863600Y508000D01* 224 | X964980Y507508D02* 225 | X964980Y457472D01* 226 | X964980Y507508D02* 227 | X965200Y508000D01* 228 | X964980Y457472D02* 229 | X864908Y457472D01* 230 | X863600Y457200D01* 231 | X964980Y457472D02* 232 | X965200Y457200D01* 233 | X964980Y609367D02* 234 | X864908Y609367D01* 235 | X964980Y609367D02* 236 | X965200Y609600D01* 237 | X864908Y609367D02* 238 | X863600Y609600D01* 239 | X863121Y661190D02* 240 | X863121Y761262D01* 241 | X863600Y762000D01* 242 | X863121Y661190D02* 243 | X863600Y660400D01* 244 | X863121Y353826D02* 245 | X863121Y305577D01* 246 | X863600Y304800D01* 247 | X863121Y353826D02* 248 | X863600Y355600D01* 249 | X964980Y353826D02* 250 | X964980Y305577D01* 251 | X964980Y353826D02* 252 | X965200Y355600D01* 253 | X964980Y305577D02* 254 | X864908Y305577D01* 255 | X863600Y304800D01* 256 | X964980Y305577D02* 257 | X965200Y304800D01* 258 | X964980Y201931D02* 259 | X964980Y153682D01* 260 | X965200Y152400D01* 261 | X964980Y201931D02* 262 | X965200Y203200D01* 263 | X825594Y114368D02* 264 | X775558Y114368D01* 265 | X825594Y114368D02* 266 | X863121Y151895D01* 267 | X775558Y114368D02* 268 | X774700Y114300D01* 269 | X863121Y151895D02* 270 | X863600Y152400D01* 271 | X863121Y76841D02* 272 | X863121Y51823D01* 273 | X863121Y76841D02* 274 | X825594Y114368D01* 275 | X863121Y51823D02* 276 | X863600Y50800D01* 277 | X864908Y51823D02* 278 | X964980Y51823D01* 279 | X965200Y50800D01* 280 | X864908Y51823D02* 281 | X863600Y50800D01* 282 | X863121Y153682D02* 283 | X863121Y201931D01* 284 | X863600Y203200D01* 285 | X863121Y153682D02* 286 | X863600Y152400D01* 287 | X864908Y151895D02* 288 | X964980Y151895D01* 289 | X965200Y152400D01* 290 | X864908Y151895D02* 291 | X863600Y152400D01* 292 | X698717Y189422D02* 293 | X646894Y189422D01* 294 | X698717Y189422D02* 295 | X773771Y114368D01* 296 | X774700Y114300D01* 297 | X482490Y62545D02* 298 | X444963Y62545D01* 299 | X482490Y62545D02* 300 | X491425Y53610D01* 301 | X739818Y53610D01* 302 | X773771Y87563D01* 303 | X444963Y62545D02* 304 | X444500Y63500D01* 305 | X773771Y87563D02* 306 | X774700Y88900D01* 307 | X621876Y680847D02* 308 | X621876Y684421D01* 309 | X621876Y680847D02* 310 | X605793Y664764D01* 311 | X605793Y605793D01* 312 | X616515Y595071D01* 313 | X632598Y595071D01* 314 | X643320Y584349D01* 315 | X643320Y407436D01* 316 | X402075Y166191D01* 317 | X394927Y166191D01* 318 | X621876Y684421D02* 319 | X622300Y685800D01* 320 | X394927Y166191D02* 321 | X393700Y165100D01* 322 | X259115Y101859D02* 323 | X141173Y101859D01* 324 | X259115Y101859D02* 325 | X282346Y125090D01* 326 | X353826Y125090D01* 327 | X393140Y164404D01* 328 | X141173Y101859D02* 329 | X139700Y101600D01* 330 | X393140Y164404D02* 331 | X393700Y165100D01* 332 | X318086Y89350D02* 333 | X469981Y89350D01* 334 | X545035Y164404D01* 335 | X318086Y89350D02* 336 | X317500Y88900D01* 337 | X545035Y164404D02* 338 | X546100Y165100D01* 339 | X750540Y253754D02* 340 | X913157Y253754D01* 341 | X914400Y254000D01* 342 | X750540Y253754D02* 343 | X749300Y254000D01* 344 | X775558Y582562D02* 345 | X889926Y582562D01* 346 | X913157Y559331D01* 347 | X775558Y582562D02* 348 | X774700Y584200D01* 349 | X913157Y559331D02* 350 | X914400Y558800D01* 351 | X621876Y482490D02* 352 | X285920Y482490D01* 353 | X214440Y411010D02* 354 | X210866Y407436D01* 355 | X214440Y411010D02* 356 | X285920Y482490D01* 357 | X621876Y482490D02* 358 | X622300Y482600D01* 359 | X210866Y407436D02* 360 | X209700Y406800D01* 361 | X209079Y275198D02* 362 | X209079Y268050D01* 363 | X209079Y275198D02* 364 | X198357Y285920D01* 365 | X198357Y394927D01* 366 | X209079Y405649D01* 367 | X209079Y268050D02* 368 | X209700Y267100D01* 369 | X209079Y405649D02* 370 | X209700Y406800D01* 371 | X209079Y473555D02* 372 | X209079Y545035D01* 373 | X209079Y473555D02* 374 | X198357Y462833D01* 375 | X198357Y427093D01* 376 | X214440Y411010D01* 377 | X209079Y545035D02* 378 | X209700Y546500D01* 379 | X214440Y411010D02* 380 | X209700Y406800D01* 381 | X209079Y612941D02* 382 | X209079Y684421D01* 383 | X209079Y612941D02* 384 | X198357Y602219D01* 385 | X198357Y557544D01* 386 | X209079Y546822D01* 387 | X209079Y684421D02* 388 | X209700Y686200D01* 389 | X209079Y546822D02* 390 | X209700Y546500D01* 391 | X316299Y160830D02* 392 | X316299Y141173D01* 393 | X316299Y160830D02* 394 | X210866Y266263D01* 395 | X316299Y141173D02* 396 | X317500Y139700D01* 397 | X210866Y266263D02* 398 | X209700Y267100D01* 399 | X623663Y634385D02* 400 | X627237Y634385D01* 401 | X768410Y493212D01* 402 | X809511Y493212D01* 403 | X895287Y407436D01* 404 | X913157Y407436D01* 405 | X623663Y634385D02* 406 | X622300Y635000D01* 407 | X913157Y407436D02* 408 | X914400Y406400D01* 409 | X621876Y532526D02* 410 | X310938Y532526D01* 411 | X210866Y432454D01* 412 | X621876Y532526D02* 413 | X622300Y533400D01* 414 | X210866Y432454D02* 415 | X209700Y431800D01* 416 | X221588Y559331D02* 417 | X621876Y559331D01* 418 | X221588Y559331D02* 419 | X210866Y570053D01* 420 | X621876Y559331D02* 421 | X622300Y558800D01* 422 | X210866Y570053D02* 423 | X209700Y571500D01* 424 | X623663Y514656D02* 425 | X623663Y509295D01* 426 | X623663Y514656D02* 427 | X639746Y530739D01* 428 | X639746Y562905D01* 429 | X629024Y573627D01* 430 | X377057Y573627D01* 431 | X241245Y709439D01* 432 | X210866Y709439D01* 433 | X622300Y508000D02* 434 | X623663Y509295D01* 435 | X210866Y709439D02* 436 | X209700Y711200D01* 437 | M02* 438 | -------------------------------------------------------------------------------- /PCB/gerbers/F.Mask.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | %ADD10C,3.363200*% 10 | %ADD11C,5.153200*% 11 | %ADD12P,2.034460X8X112.500000*% 12 | %ADD13P,1.649562X8X112.500000*% 13 | %ADD14P,1.649562X8X292.500000*% 14 | %ADD15C,1.511200*% 15 | %ADD16C,1.511200*% 16 | %ADD17C,2.146300*% 17 | %ADD18C,1.879600*% 18 | %ADD19R,3.003200X3.003200*% 19 | %ADD20P,2.556822X8X22.500000*% 20 | 21 | 22 | D10* 23 | X474750Y771550D03* 24 | X347750Y771550D03* 25 | D11* 26 | X530400Y619150D03* 27 | X292100Y619150D03* 28 | X530400Y396850D03* 29 | X292100Y396850D03* 30 | D12* 31 | X774700Y88900D03* 32 | X774700Y114300D03* 33 | D13* 34 | X393700Y63500D03* 35 | X393700Y165100D03* 36 | D14* 37 | X444500Y165100D03* 38 | X444500Y63500D03* 39 | X495300Y165100D03* 40 | X495300Y63500D03* 41 | X546100Y165100D03* 42 | X546100Y63500D03* 43 | D15* 44 | X768160Y406400D02* 45 | X781240Y406400D01* 46 | X781240Y431800D02* 47 | X768160Y431800D01* 48 | X768160Y457200D02* 49 | X781240Y457200D01* 50 | X781240Y482600D02* 51 | X768160Y482600D01* 52 | X768160Y508000D02* 53 | X781240Y508000D01* 54 | X781240Y533400D02* 55 | X768160Y533400D01* 56 | X768160Y558800D02* 57 | X781240Y558800D01* 58 | X781240Y584200D02* 59 | X768160Y584200D01* 60 | X768160Y609600D02* 61 | X781240Y609600D01* 62 | X781240Y635000D02* 63 | X768160Y635000D01* 64 | X768160Y660400D02* 65 | X781240Y660400D01* 66 | X781240Y685800D02* 67 | X768160Y685800D01* 68 | X628840Y406400D02* 69 | X615760Y406400D01* 70 | X615760Y431800D02* 71 | X628840Y431800D01* 72 | X628840Y457200D02* 73 | X615760Y457200D01* 74 | X615760Y609600D02* 75 | X628840Y609600D01* 76 | X628840Y635000D02* 77 | X615760Y635000D01* 78 | X615760Y660400D02* 79 | X628840Y660400D01* 80 | X628840Y685800D02* 81 | X615760Y685800D01* 82 | X615760Y762000D02* 83 | X628840Y762000D01* 84 | X768160Y762000D02* 85 | X781240Y762000D01* 86 | X781240Y736600D02* 87 | X768160Y736600D01* 88 | X768160Y711200D02* 89 | X781240Y711200D01* 90 | X628840Y736600D02* 91 | X615760Y736600D01* 92 | X615760Y711200D02* 93 | X628840Y711200D01* 94 | X628840Y482600D02* 95 | X615760Y482600D01* 96 | D16* 97 | X673100Y419100D03* 98 | X698500Y419100D03* 99 | X723900Y419100D03* 100 | D15* 101 | X628840Y584200D02* 102 | X615760Y584200D01* 103 | X615760Y558800D02* 104 | X628840Y558800D01* 105 | X628840Y533400D02* 106 | X615760Y533400D01* 107 | X615760Y508000D02* 108 | X628840Y508000D01* 109 | D16* 110 | X673100Y393700D03* 111 | X698500Y393700D03* 112 | X723900Y393700D03* 113 | D17* 114 | X914400Y711200D03* 115 | X965200Y762000D03* 116 | X863600Y762000D03* 117 | X863600Y660400D03* 118 | X965200Y660400D03* 119 | X914400Y558800D03* 120 | X965200Y609600D03* 121 | X863600Y609600D03* 122 | X863600Y508000D03* 123 | X965200Y508000D03* 124 | X914400Y254000D03* 125 | X965200Y304800D03* 126 | X863600Y304800D03* 127 | X863600Y203200D03* 128 | X965200Y203200D03* 129 | X914400Y101600D03* 130 | X965200Y152400D03* 131 | X863600Y152400D03* 132 | X863600Y50800D03* 133 | X965200Y50800D03* 134 | X914400Y406400D03* 135 | X965200Y457200D03* 136 | X863600Y457200D03* 137 | X863600Y355600D03* 138 | X965200Y355600D03* 139 | D18* 140 | X209700Y267100D03* 141 | X209700Y292100D03* 142 | X209700Y317100D03* 143 | D19* 144 | X139700Y337100D03* 145 | X139700Y247100D03* 146 | D18* 147 | X209700Y686200D03* 148 | X209700Y711200D03* 149 | X209700Y736200D03* 150 | D19* 151 | X139700Y756200D03* 152 | X139700Y666200D03* 153 | D18* 154 | X209700Y546500D03* 155 | X209700Y571500D03* 156 | X209700Y596500D03* 157 | D19* 158 | X139700Y616500D03* 159 | X139700Y526500D03* 160 | D18* 161 | X209700Y406800D03* 162 | X209700Y431800D03* 163 | X209700Y456800D03* 164 | D19* 165 | X139700Y476800D03* 166 | X139700Y386800D03* 167 | D20* 168 | X647700Y254000D03* 169 | X749300Y254000D03* 170 | X317500Y139700D03* 171 | X317500Y88900D03* 172 | X596900Y139700D03* 173 | X596900Y88900D03* 174 | X139700Y127000D03* 175 | X139700Y101600D03* 176 | X266700Y88900D03* 177 | X266700Y139700D03* 178 | M02* 179 | -------------------------------------------------------------------------------- /PCB/gerbers/F.Paste.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | 10 | 11 | M02* 12 | -------------------------------------------------------------------------------- /PCB/gerbers/drills.xln: -------------------------------------------------------------------------------- 1 | M48 2 | ;GenerationSoftware,Autodesk,EAGLE,9.0.1*% 3 | ;CreationDate,2018-07-03T15:16:02Z*% 4 | FMAT,2 5 | ICI,OFF 6 | METRIC,TZ,000.000 7 | T8C0.800 8 | T7C0.813 9 | T6C1.016 10 | T5C1.100 11 | T4C1.295 12 | T3C1.600 13 | T2C2.110 14 | T1C3.300 15 | % 16 | G90 17 | M71 18 | T1 19 | X53040Y61915 20 | X29210Y61915 21 | X53040Y39685 22 | X29210Y39685 23 | T2 24 | X47475Y77155 25 | X34775Y77155 26 | T3 27 | X13970Y38680 28 | X13970Y47680 29 | X13970Y52650 30 | X13970Y61650 31 | X13970Y66620 32 | X13970Y75620 33 | X13970Y24710 34 | X13970Y33710 35 | T4 36 | X86360Y60960 37 | X96520Y60960 38 | X91440Y55880 39 | X96520Y66040 40 | X86360Y66040 41 | X86360Y76200 42 | X91440Y71120 43 | X86360Y20320 44 | X96520Y76200 45 | X86360Y30480 46 | X96520Y30480 47 | X91440Y25400 48 | X96520Y50800 49 | X86360Y50800 50 | X96520Y20320 51 | X96520Y35560 52 | X86360Y35560 53 | X86360Y45720 54 | X96520Y45720 55 | X91440Y40640 56 | X96520Y5080 57 | X86360Y5080 58 | X86360Y15240 59 | X96520Y15240 60 | X91440Y10160 61 | T5 62 | X20970Y40680 63 | X20970Y45680 64 | X20970Y43180 65 | X20970Y26710 66 | X20970Y29210 67 | X20970Y31710 68 | X20970Y68620 69 | X20970Y71120 70 | X20970Y73620 71 | X20970Y54650 72 | X20970Y57150 73 | X20970Y59650 74 | T6 75 | X26670Y8890 76 | X13970Y10160 77 | X13970Y12700 78 | X59690Y8890 79 | X59690Y13970 80 | X31750Y8890 81 | X74930Y25400 82 | X26670Y13970 83 | X64770Y25400 84 | X31750Y13970 85 | T7 86 | X77470Y8890 87 | X77470Y11430 88 | X39370Y6350 89 | X39370Y16510 90 | X44450Y16510 91 | X44450Y6350 92 | X49530Y16510 93 | X54610Y6350 94 | X54610Y16510 95 | X49530Y6350 96 | T8 97 | X77470Y40640 98 | X77470Y43180 99 | X77470Y45720 100 | X77470Y48260 101 | X77470Y50800 102 | X62230Y73660 103 | X62230Y71120 104 | X77470Y71120 105 | X77470Y73660 106 | X77470Y76200 107 | X77470Y68580 108 | X62230Y50800 109 | X62230Y53340 110 | X62230Y55880 111 | X77470Y66040 112 | X77470Y63500 113 | X62230Y58420 114 | X72390Y41910 115 | X69850Y41910 116 | X77470Y60960 117 | X77470Y58420 118 | X69850Y39370 119 | X62230Y40640 120 | X62230Y48260 121 | X77470Y55880 122 | X77470Y53340 123 | X72390Y39370 124 | X62230Y43180 125 | X67310Y39370 126 | X62230Y45720 127 | X62230Y60960 128 | X62230Y63500 129 | X62230Y66040 130 | X62230Y68580 131 | X62230Y76200 132 | X67310Y41910 133 | M30 -------------------------------------------------------------------------------- /PCB/gerbers/gerber_job.gbrjob: -------------------------------------------------------------------------------- 1 | G04 Gerber job file.* 2 | %TF.FileFunction,JobInfo*% 3 | %TF.GenerationSoftware,Autodesk,EAGLE,9.0.1*% 4 | %TF.CreationDate,2018-07-03T15:16:02Z*% 5 | %TF.Part,Single*% 6 | %MOMM*% 7 | %TJ.B_Owner,Andre Maia Chagas *% 8 | %TJ.B_ID,Spikeling PCB*% 9 | %TJ.B_LayerNum,2*% 10 | %TJ.B_Thickness,1.570000*% 11 | %TJ.B_Size_X,96.190000*% 12 | %TJ.B_Size_Y,78.730000*% 13 | M02* -------------------------------------------------------------------------------- /PCB/gerbers/profile.gbr: -------------------------------------------------------------------------------- 1 | G04 EAGLE Gerber X2 export* 2 | G75* 3 | %MOMM*% 4 | %FSLAX34Y34*% 5 | %LPD*% 6 | %AMOC8* 7 | 5,1,8,0,0,1.08239X$1,22.5*% 8 | G01* 9 | %ADD10C,0.254000*% 10 | 11 | 12 | D10* 13 | X50800Y12700D02* 14 | X1012700Y12700D01* 15 | X1012700Y800000D01* 16 | X50800Y800000D01* 17 | X50800Y12700D01* 18 | X129200Y378800D02* 19 | X150200Y378800D01* 20 | X150200Y394800D01* 21 | X129200Y394800D01* 22 | X129200Y378800D01* 23 | X129200Y468800D02* 24 | X150200Y468800D01* 25 | X150200Y484800D01* 26 | X129200Y484800D01* 27 | X129200Y468800D01* 28 | X129200Y518500D02* 29 | X150200Y518500D01* 30 | X150200Y534500D01* 31 | X129200Y534500D01* 32 | X129200Y518500D01* 33 | X129200Y608500D02* 34 | X150200Y608500D01* 35 | X150200Y624500D01* 36 | X129200Y624500D01* 37 | X129200Y608500D01* 38 | X129200Y658200D02* 39 | X150200Y658200D01* 40 | X150200Y674200D01* 41 | X129200Y674200D01* 42 | X129200Y658200D01* 43 | X129200Y748200D02* 44 | X150200Y748200D01* 45 | X150200Y764200D01* 46 | X129200Y764200D01* 47 | X129200Y748200D01* 48 | X129200Y329100D02* 49 | X150200Y329100D01* 50 | X150200Y345100D01* 51 | X129200Y345100D01* 52 | X129200Y329100D01* 53 | X129200Y239100D02* 54 | X150200Y239100D01* 55 | X150200Y255100D01* 56 | X129200Y255100D01* 57 | X129200Y239100D01* 58 | M02* 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Welcome to the official Spikeling GitHub 3 | 4 | Understanding of how neurons encode and compute information is fundamental to our study of the brain, but opportunities for hands-on experience with neurophysiological techniques on live neurons are scarce in science education. Here, we present Spikeling, an open source £25 in silico implementation of a spiking neuron that mimics a wide range of neuronal behaviours for classroom education and public neuroscience outreach. 5 | 6 | For details, please refer to 7 | - the main manuscript on BioRxiv [here](https://www.biorxiv.org/content/early/2018/05/21/327502) 8 | - the entry on Open Labware [here](https://open-labware.net/projects/spikeling/) 9 | 10 | ![Spikeling in action](https://openlabwaredotnet.files.wordpress.com/2018/05/spikeling-picci.png) 11 | 12 | 13 | Spikeling is based on an Arduino microcontroller running the computationally efficient Izhikevich model of a spiking neuron. The microcontroller is connected to input ports that simulate synaptic excitation or inhibition, dials controlling current injection and noise levels, a photodiode that makes Spikeling light-sensitive and an LED and speaker that allows spikes to be seen and heard. Output ports provide access to variables such as membrane potential for recording in experiments or digital signals that can be used to excite other connected Spikelings. These features allow for the intuitive exploration of the function of neurons and networks. 14 | 15 | # Files 16 | 17 | In this repository and the associated publication (linked above) you will find all files needed to build a Spikeling, get started with it and do some basic data analysis. 18 | -------------------------------------------------------------------------------- /Serial Oscilloscope (PC).zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/Serial Oscilloscope (PC).zip -------------------------------------------------------------------------------- /Spikeling manual and exercises.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/Spikeling manual and exercises.docx -------------------------------------------------------------------------------- /Spikeling manual and exercises.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BadenLab/Spikeling/05ed23187e42204304b7ff6d435eb4cd60a2c97c/Spikeling manual and exercises.pdf -------------------------------------------------------------------------------- /kitspace.yaml: -------------------------------------------------------------------------------- 1 | summary: A hardware implementation of the Izhikevich model of a spiking neuron 2 | site: https://open-labware.net/projects/spikeling/ 3 | color: green 4 | bom: 1-click_BOM.tsv 5 | gerbers: PCB/gerbers 6 | -------------------------------------------------------------------------------- /okh-spikeling.yml: -------------------------------------------------------------------------------- 1 | # The content of this manifest file is licensed under a Creative Commons Attribution 4.0 International License. 2 | # Licenses for modification and distribution of the hardware, documentation, source-code, etc are stated separately. 3 | 4 | # Remove any fields that are not used. Comments (beginning with '#') may also be removed. 5 | 6 | # Manifest metadata 7 | 8 | date-created: 2019-10-15 # YYYY-MM-DD 9 | 10 | #date-updated: [value] # YYYY-MM-DD 11 | 12 | manifest-author: 13 | name: Andre Maia Chagas # required | text 14 | affiliation: University of Sussex # text 15 | email: a.maia-chagas@sussex.ac.uk # email address 16 | 17 | manifest-language: en-UK 18 | 19 | documentation-language: en-UK 20 | 21 | #manifest-is-translation: 22 | # title: [value] # text | Title of the original 23 | # manifest: [value] # URL - Absolute path | OKH manifest location 24 | # web: [value] # URL - Absolute path | web presence location 25 | # lang: [language]-[region] # language of original 26 | 27 | #documentation-is-translation: 28 | # title: [value] # text | Title of the original 29 | # manifest: [value] # URL - Absolute path | OKH manifest location 30 | # web: [value] # URL - Absolute path | web presence location 31 | # lang: [language]-[region] # language of original 32 | 33 | # Properties 34 | 35 | title: Spikeling 36 | 37 | description: | 38 | A hardware implementation of the Izhikevich model of a spiking neuron. 39 | Understanding of how neurons encode and compute information is fundamental to our study of the brain, 40 | but opportunities for hands-on experience with neurophysiological techniques on live neurons are scarce in science education. 41 | Here, we present Spikeling, an open source £25 in silico implementation of a spiking neuron that mimics a wide range of neuronal behaviours 42 | for classroom education and public neuroscience outreach. 43 | intended-use: | 44 | Spikeling is a device for teaching how neurons work 45 | keywords: # At least one keyword is recommended | text array 46 | - neuroscience 47 | - open science 48 | 49 | project-link: https://github.com/BadenLab/Spikeling # At least project-link or documentation-home is required, otherwise recommended | absolute path URL 50 | 51 | #health-safety-notice: | # paragraph 52 | # [value] 53 | 54 | contact: 55 | name: Tom Baden # text 56 | affiliation: University of Sussex # text 57 | email: t.baden@sussex.ac.uk # email address 58 | social: 59 | - platform: Twitter # text 60 | user-handle: "@NeuroFishh" # text 61 | 62 | #contributors: # recommended 63 | # - name: [contributor 1] # text 64 | # affiliation: [value] # text 65 | # email: [value] # email address 66 | 67 | image: https://camo.githubusercontent.com/0f0fe711eb32d4678433a7b401d66bbfd8709127/68747470733a2f2f6f70656e6c616277617265646f746e65742e66696c65732e776f726470726573732e636f6d2f323031382f30352f7370696b656c696e672d70696363692e706e67 # recommended | absolute or relative path 68 | 69 | version: 1.0 # text 70 | 71 | #development-stage: [value] # text 72 | 73 | made: true # boolean - true or false 74 | 75 | made-independently: true # boolean - true or false 76 | 77 | #standards-used: 78 | # - standard-title: [value] # Required where used | Title of the standard used in developing the design or documentation 79 | # publisher: [value] # Publisher of the standard 80 | # reference: [value] # Reference indentifier of the standard (e.g. ISO 9001) 81 | # certification: # If certification has been granted confirming compliance with the standard 82 | # - certifier: [value] # Individual or organisation granting the certification. Use "Self" for self-certification 83 | # date-awarded: [value] # Date certification was granted 84 | # link: [value] # Link to evidence of certification (e.g. certificate). Use an an absolute path to an external resource or an absolute or relative path to evidence within the documentation. 85 | 86 | #derivative-of: 87 | # title: [value] # text | Title of the original 88 | # manifest: [value] # URL - Absolute path | OKH manifest location 89 | # web: [value] # URL - Absolute path | web presence location 90 | 91 | #variant-of: 92 | # title: [value] # text | Title of the original 93 | # manifest: [value] # URL - Absolute path | OKH manifest location 94 | # web: [value] # URL - Absolute path | web presence location 95 | 96 | #sub: 97 | # title: [sub 1] # text | Title of the original 98 | # manifest: [value] # URL - Absolute path | OKH manifest location 99 | # web: [value] # URL - Absolute path | web presence location 100 | 101 | # License 102 | 103 | license: # At least one license is required | The format should be an SPDX identifier. See https://spdx.org/licenses/hardware: [value] # recommended | The license under which the hardware is released 104 | hardware: CERN-OHL-1.2 # recommended | The license under which the documentation is released 105 | documentation: MIT # recommended | The license under which the documentation is released 106 | software: CC-BY-SA-4.0 # recommended where software is used | The license under which the software is released 107 | 108 | licensor: 109 | name: Tom Baden # text 110 | affiliation: University of Sussex # text 111 | email: t.baden@sussex.ac.uk # email address 112 | 113 | # Documentation 114 | 115 | documentation-home: https://github.com/BadenLab/Spikeling # At least one of the project-link or documentation-home fields is required | absolute path 116 | 117 | #archive-download: [value] # Absolute or relative path 118 | 119 | #design-files: # recommended 120 | # - path: [value] # Absolute or relative path 121 | # title: [value] # text 122 | 123 | #schematics: # recommended where applicable 124 | # - path: [value] # Absolute or relative path 125 | # title: [value] # text 126 | 127 | bom: 1-click_BOM.tsv # recommended | absolute or relative path | Direct the maker to the Bill of Materials 128 | 129 | #tool-list: [value] # recommended | absolute or relative path | Direct the maker to a list of tools required to make the thing 130 | 131 | making-instructions: # recommended 132 | - path: Spikeling manual and exercises.pdf # Absolute or relative path 133 | title: Spikeling manual and exercises # text 134 | 135 | #manufacturing-files: # recommended where applicable 136 | # - path: [value] # Absolute or relative path 137 | # title: [value] # text 138 | 139 | #risk-assessment: # recommended 140 | # - path: [value] # Absolute or relative path 141 | # title: [value] # text 142 | 143 | #tool-settings: # recommended where applicable 144 | # - path: [value] # Absolute or relative path 145 | # title: [value] # text 146 | 147 | #quality-instructions: 148 | # - path: [value] # Absolute or relative path 149 | # title: [value] # text 150 | 151 | #operating-instructions: # recommended 152 | # - path: [value] # Absolute or relative path 153 | # title: [value] # text 154 | 155 | #maintenance-instructions: [value] # recommended 156 | # - path: [value] # Absolute or relative path 157 | # title: [value] # text 158 | 159 | #disposal-instructions: [value] # recommended 160 | # - path: [value] # Absolute or relative path 161 | # title: [value] # text 162 | 163 | #software: # recommended where applicable | Source code or executable software that the thing uses 164 | # - path: [value] # Absolute or relative path 165 | # title: [value] # text 166 | 167 | # User defined Fields 168 | # Include any custom / extended fields here 169 | --------------------------------------------------------------------------------