Guest User

NeuroBytes v07 runtime draft

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