Advertisement
Guest User

NeuroBytes v07 runtime draft

a guest
Jan 31st, 2016
300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.56 KB | None | 0 0
  1. /*
  2.     NeuroBytes v07 runtime program
  3.     Includes integer-ized and approximated Izhikevich dynamics. Drives the RGB LED using software PWM.
  4.     Copyright 2016, Zach Fredin
  5.     zach@neurotinker.com
  6.     Revision 1/21/2016
  7.     Distributed under terms of the GNU General Public License, version 3.
  8.  
  9.     This file is part of NeuroBytes.
  10.  
  11.     NeuroBytes is free software: you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License as published by
  13.     the Free Software Foundation, either version 3 of the License, or
  14.     (at your option) any later version.
  15.  
  16.     NeuroBytes is distributed in the hope that it will be useful,
  17.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.     GNU General Public License for more details.
  20.  
  21.     You should have received a copy of the GNU General Public License
  22.     along with NeuroBytes.  If not, see <http://www.gnu.org/licenses/>.
  23. */
  24.  
  25. #include <avr/io.h>
  26. #include <avr/interrupt.h>
  27.  
  28. /*  ________________________________________
  29.     |                                       \
  30.     | |DEND1| |DEND2|  NeuroBytes v0.7       \
  31.     |                                 |AXON1| \
  32.     |                                         |
  33.     |                            D1           |
  34.     |                          R G B          |
  35.     |                                 |AXON2| /
  36.     | |DEND3| |DEND4|                        /
  37.     |_______________________________________/
  38.  
  39.     DEND1-SIG   PD6     DEND1-TYPE  PD5
  40.     DEND2-SIG   PB7     DEND2-TYPE  PB6
  41.     DEND3-SIG   PB0     DEND3-TYPE  PD7
  42.     DEND4-SIG   PB1     DEND4-TYPE  PB2
  43.  
  44.     AXON1-SIG   PD0     AXON1-TYPE  PC5
  45.     AXON2-SIG   PC1     AXON2-TYPE  PC0
  46.  
  47.     D1-RED      PC3
  48.     D1-GRN      PC4
  49.     D1-BLU      PC2
  50. */
  51.  
  52. /*
  53.     for a=5,b=2,c=-65,d=8,E=6,F=2,G=16,H=161:
  54.     I   v (if stable)   fire rate (Hz, 1ms cycles, avg over 500)
  55.     0   -102        0
  56.     1   -101        0
  57.     2   -100        0
  58.     3   -99     0
  59.     4   -99     0
  60.     5   -98     0
  61.     6   -97     0
  62.     7   -96     0
  63.     8   -95     0
  64.     9   -95     0
  65.     10  -94     0
  66.     11  -93     0
  67.     12  -92     0
  68.     13  -91     0
  69.     14  -91     0
  70.     15  -90     0
  71.     16  -89     0
  72.     17  -87     0
  73.     18  -86     0
  74.     19  -86     0
  75.     20  -85     0
  76.     21  -83     0
  77.     22  -81     0
  78.     23  -81     0
  79.     24  -79     0
  80.     25  -77     0
  81.     26  -77     0
  82.     27  -75     0
  83.     28  -71     0
  84.     29  -71     0
  85.     30  n/a     28
  86.     31  n/a     36
  87.     32  n/a     36
  88.     33  n/a     44
  89.     34  n/a     50
  90.     35  n/a     50
  91.     36  n/a     50
  92.     37  n/a     52
  93.     38  n/a     60
  94.     39  n/a     60
  95.     40  n/a     60
  96.     41  n/a     68
  97.     42  n/a     72
  98.     43  n/a     72
  99.     44  n/a     76
  100.     45  n/a     76
  101.     46  n/a     76
  102.     47  n/a     76
  103.     48  n/a     76
  104.     49  n/a     76
  105.     50  n/a     80
  106. */ 
  107.    
  108. /*  Izhikevich model parameters and coefficients */
  109. const int16_t a = 5;
  110. const int16_t b = 2;
  111. const int16_t c = -65;
  112. const int16_t d = 8;
  113. const int16_t E = 6;
  114. const int16_t F = 2;
  115. const int16_t G = 16;
  116. const int16_t H = 161;
  117.  
  118. /*  Izhikevich model variables */
  119. volatile int8_t I;
  120. volatile int8_t I_rest = 21;
  121. volatile int16_t v = -65;
  122. volatile int16_t u = 0;
  123.  
  124. /*  Intra-model variables */
  125. volatile int16_t vSq = 0;
  126. volatile int16_t vF = 0;
  127. volatile uint8_t modelStage = 0;
  128. volatile int16_t v_prev;
  129. volatile int16_t u_prev;
  130.  
  131. /*  Neuron variables */
  132. volatile uint8_t firing = 0;
  133. volatile uint8_t fireTimer = 0;
  134. const uint8_t axonPulseLength = 5;
  135. volatile unsigned char dendStatus = 0; //current status of four dendrites, including types
  136. volatile unsigned char dendStatusPrev = 0; //previous dendrite status/type
  137. volatile int8_t val_Dend[4]; //keeps track of current dendrite's contribution to I (positive or negative)
  138. volatile uint8_t stg_Dend[4] = {0,0,0,0}; //current stage of each dendrite impulse: 0 is REST, 1 is HOLD, 2 is DECAY
  139. const int8_t hldTime_Dend[4] = {20,20,20,20};
  140. volatile int8_t hldTimeCur_Dend[4];
  141. const int8_t hldVal_Dend[4] = {10,10,10,10};
  142. const int8_t dec_Dend[4] = {2,2,2,2};
  143.  
  144. /*  LED variables */
  145. volatile uint8_t LED[3] = {0,0,0}; //R,G,B, 0-100
  146. volatile uint8_t LEDtick = 0; //0-100
  147. volatile uint8_t LEDfade[3][61] = {//fader for -102 <= v < -41, where I=21 (v=-83) is rest (pure green). R,G,B
  148. {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,2 ,2 ,3 ,3 ,4 ,4 ,5 ,5 ,6 ,6 ,7 ,7 ,8 ,8 ,9 ,9 ,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20},
  149. {1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10,11,12,13,14,15,16,17,18,19,20,20,19,19,18,18,17,17,16,16,15,15,14,14,13,13,12,12,11,11,10,10,9 ,9 ,8 ,8 ,7 ,7 ,6 ,6 ,5 ,5 ,4 ,4 ,3 ,3 ,2 ,2 ,1 ,1 ,0 ,0 },
  150. {19,18,17,16,15,14,13,12,11,10,9 ,8 ,7 ,6 ,5 ,4 ,3 ,2 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }
  151. };
  152.  
  153. /*  Timing variables */
  154. volatile uint8_t tick = 0; //ISR flips this to non-zero to update loop
  155. const uint8_t modelUpdateFrequency = 255; //how many ticks pass before the model recalculates (higher = slower)
  156. const uint8_t modelUpdateMultiplier = 3; //multiplier for modelUpdateFrequency (since they're 8-bit unsigned integers)
  157.  
  158. void getDendrites(void) {
  159. /*  updates dendStatus to the current input value:
  160. bit MSB 6   5   4   3   2   1   LSB
  161. DEND    4   3   2   1   4   3   2   1
  162. input   SIG SIG SIG SIG TYPE    TYPE    TYPE    TYPE
  163. pin PB1 PB0 PB7 PD6 PB2 PD7 PB6 PD5
  164. */
  165.     dendStatusPrev = dendStatus;
  166.     dendStatus = 0;
  167.     dendStatus |= ((PINB & (1<<PB1))<<6);
  168.     dendStatus |= ((PINB & (1<<PB0))<<6);
  169.     dendStatus |= ((PINB & (1<<PB7))>>2);
  170.     dendStatus |= ((PIND & (1<<PD6))>>2);
  171.     dendStatus |= ((PINB & (1<<PB2))<<1);
  172.     dendStatus |= ((PIND & (1<<PD7))>>5);
  173.     dendStatus |= ((PINB & (1<<PB6))>>5);
  174.     dendStatus |= ((PIND & (1<<PD5))>>5);
  175. }
  176.  
  177. void calcDend(uint8_t dend) {
  178. /*  checks the dendrites and updates I based on hold and decay variables. function only runs on the
  179.     dendrite indicated in the argument so it can be staged via updateModel(). */
  180.     uint8_t inh = 1; //toggles to 0 if the selected dendrite is excitatory
  181.     if (dendStatus & (1<<dend)) {
  182.         inh = 0;
  183.     }
  184.     switch (stg_Dend[dend]) {
  185.         case 0: //REST
  186.             val_Dend[dend] = 0;
  187.             if (dendStatus & (1<<(dend + 4))) {
  188.                 stg_Dend[dend]++;
  189.             }  
  190.             break;
  191.         case 1: //HOLD
  192.             val_Dend[dend] = hldVal_Dend[dend];
  193.             if (dendStatus & (1<<(dend + 4))) {
  194.                 hldTimeCur_Dend[dend] = hldTime_Dend[dend];
  195.             }
  196.             else {
  197.                 hldTimeCur_Dend[dend] -= 1;
  198.                 if (hldTimeCur_Dend[dend] == 0) {
  199.                     stg_Dend[dend]++;
  200.                 }
  201.             }
  202.             break;
  203.         case 2: //DECAY
  204.             if (dendStatus & (1<<(dend + 4))) {
  205.                 stg_Dend[dend]--;
  206.             }
  207.             else {
  208.                 if ((val_Dend[dend] - dec_Dend[dend]) > 0) {
  209.                     val_Dend[dend] -= dec_Dend[dend];
  210.                 }
  211.                 else {
  212.                     stg_Dend[dend] = 0;
  213.                 }
  214.             }
  215.             break;
  216.     }
  217.     if (inh == 1) {
  218.         val_Dend[dend] = -val_Dend[dend];
  219.     }
  220. }
  221.  
  222. void calcI(void) {
  223. /*  updates I based on current dendrite values */
  224.     uint8_t i;
  225.     I = I_rest;
  226.     for (i=0;i<4;i++) {
  227.         I += val_Dend[i];  
  228.     }
  229. }
  230.  
  231. int16_t square(int16_t input) {
  232. /*  Returns the square of the input if it won't overflow a 16-bit signed integer. If it would, returns 32767.
  233.     NOTE: This function does not shut off interrupts so it may cause atomicity issues! */
  234.     if (input <= 181) {
  235.         return input * input;
  236.     }
  237.     else {
  238.         return 32767;
  239.     }
  240. }
  241.  
  242. void translateColor() {
  243. /*  translates membrane potential (v) values into the RGB array
  244.     resting membrane potential:
  245.     v < -102        pure blue
  246.     -102 <= v < -90     fade blue to green
  247.     v = -90         pure green
  248.     -90 < v =< -71      fade green to red
  249.     v > -71         firing (pure white)
  250.     Execution time: 28.9 us    
  251. */
  252.     if(v < -102) { //3.5 us
  253.         LED[0] = 0;
  254.         LED[1] = 1;
  255.         LED[2] = 20;
  256.     }
  257.     else if((v >= -102) & (v < -41)) { //24.1 us
  258.         LED[0] = LEDfade[0][(uint8_t)(v + 102)];
  259.         LED[1] = LEDfade[1][(uint8_t)(v + 102)];
  260.         LED[2] = LEDfade[2][(uint8_t)(v + 102)];
  261.     }
  262.     else {
  263.         LED[0] = 20;
  264.         LED[1] = 1;
  265.         LED[2] = 0;
  266.     }
  267. }
  268.  
  269. void updateModel(stage) {
  270. /*  This function updates the membrane potential (v) and recovery potential (u) variables based on the
  271.     current I value. Since the Izhikevich model includes a reset check to determine firing, this function
  272.     also updates the 'firing' variable to 1 when the neuron fires. The model uses 16-bit integer math, so
  273.     interrupts are temporarily disabled to maintain atomicity.
  274.     Execution time: 29.0 us max, depending on current stage. */
  275.     uint8_t temp = SREG;
  276.     cli();
  277.     if (stage == 0) {
  278.         getDendrites();
  279.     }
  280.     else if ((stage >= 1) & (stage < 5)) {
  281.         calcDend(stage - 1);
  282.     }  
  283.     else if (stage == 5) {
  284.         calcI();
  285.     }
  286.     else if (stage == 6) { //17.4 us
  287.         vSq = square(v);
  288.     }
  289.     else if (stage == 7) {
  290.         v_prev = v;
  291.         u_prev = u;
  292.         vF = v * F;
  293.     }
  294.     else if (stage == 8) { //29.0 us    
  295.         if(v_prev > H) {
  296.             v = c;
  297.             u = u_prev + d;
  298.             firing = 1;
  299.         }
  300.         else {
  301.             v = v_prev + (vSq >> E) + vF + G - u_prev + I;
  302.             u = u_prev + (((v_prev >> b) - u_prev) >> a);
  303.             firing = 0;
  304.         }
  305.     }
  306.     else if (stage == 9) { //28.9 us
  307.         translateColor();
  308.     }
  309.     SREG = temp;
  310. }
  311.  
  312. void updateLED(void) {
  313. /*  Updates the RGB LED based on the current membrane potential value. Uses PWM fading and global variables to
  314.     figure out when the various elements should be on. Resolution controlled by LEDtick reset.
  315.     Execution time: 5.6 us */
  316.     if(LED[0] > LEDtick) {
  317.         PORTC &= ~(1<<PC3);
  318.     }
  319.     else {
  320.         PORTC |= (1<<PC3);
  321.     }
  322.     if(LED[1] > LEDtick) {
  323.         PORTC &= ~(1<<PC4);
  324.     }
  325.     else {
  326.         PORTC |= (1<<PC4);
  327.     }
  328.     if(LED[2] > LEDtick) {
  329.         PORTC &= ~(1<<PC2);
  330.     }
  331.     else {
  332.         PORTC |= (1<<PC2);
  333.     }
  334.     LEDtick++;   
  335.     if (LEDtick > 100) {
  336.         LEDtick = 0;
  337.     }  
  338. }
  339.  
  340. ISR(TIMER0_COMPA_vect) {
  341. /* Makes ticks fire at a regular interval in the main loop. */
  342.     tick = 1;
  343. }
  344.  
  345. void systemInit(void) {
  346. /* set up D1 */
  347.     DDRC |= ((1<<PC2) | (1<<PC3) | (1<<PC4));
  348.     PORTC |= ((1<<PC2) | (1<<PC3) | (1<<PC4)); //set pins = LED off
  349.  
  350. /* set up dendrites */
  351.     DDRB &= ~((1<<PB7) | (1<<PB0) | (1<<PB1) | (1<<PB6) | (1<<PB2));
  352.     DDRD &= ~((1<<PD5) | (1<<PD6) | (1<<PD7));
  353. /* set up axons */
  354.     DDRD |= (1<<PD0);
  355.     DDRC |= ((1<<PC1) | (1<<PC0) | (1<<PC5));
  356.     PORTC |= ((1<<PC0) | (1<<PC5)); //set type pins
  357.  
  358. /* set up Timer/Counter0 */
  359.     TCCR0A |= ((1<<CTC0) | (1<<CS00) | (1<<CS01)); //CTC, clk/64
  360.     TCNT0 = 0;
  361.     OCR0A = 4; //loop time = 8 * (OCR0A + 1) uS
  362.     TIMSK0 |= (1<<OCIE0A); //enables Output Compare Match A ISR
  363.  
  364. /* misc */
  365.     sei(); //enable global interrupts
  366. }
  367.  
  368. void fire(void) {
  369.     PORTC &= ~((1<<PC2) | (1<<PC3) | (1<<PC4));
  370.     fireTimer = axonPulseLength;
  371. }
  372.  
  373. int main(void) {
  374.     systemInit();
  375.     uint8_t i = 0; //counters for update delay
  376.     uint8_t j = 0;
  377.     for(;;) {
  378.         while(tick == 0) { /* idle loop */ }
  379.         /* This stuff happens every 40 uS or so */
  380.         tick = 0;
  381.         if (i < 10) {
  382.             updateModel(i);
  383.         }
  384.         if (firing == 0) {
  385.             updateLED(); //5.6 us
  386.         }
  387.         else {
  388.             fire();
  389.         }
  390.         j++;
  391.         if (j == modelUpdateMultiplier) {
  392.             i++;
  393.             j = 0;
  394.         }
  395.         if (i == modelUpdateFrequency) {
  396.             i = 0;
  397.             if (fireTimer > 0) {
  398.                 PORTD |= (1<<PD0);
  399.                 PORTC |= (1<<PC1);
  400.                 fireTimer--;
  401.             }
  402.             else {
  403.                 PORTD &= ~(1<<PD0);
  404.                 PORTC &= ~(1<<PC1);
  405.             }
  406.         }
  407.     }
  408. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement