示例#1
0
void user_loop(void)
{
   unsigned char channel;

   /* loop over all HV channels */
   for (channel=0 ; channel<N_HV_CHN ; channel++) {

      watchdog_refresh(0);

      if ((user_data[0].control & CONTROL_IDLE) == 0) {

         /* read back HV and current */
         read_hv(channel);
         read_current(channel);

         /* check for current trip */
         check_current(channel);

         /* do ramping and regulation */
         ramp_hv(channel);
         regulation(channel);

         /* set voltage regularly, in case DAC hot HV spike */
         set_hv(channel, user_data[channel].u_dac);
      }
   }

   // read_temperature();
}
示例#2
0
extern "C" int main()
{
    pinMode(LED_BUILTIN, OUTPUT);
    leds.begin();

    // Announce firmware version
    serial_begin(BAUD2DIV(115200));
    serial_print("Fadecandy v" DEVICE_VER_STRING "\r\n");

    // Application main loop
    while (usb_dfu_state == DFU_appIDLE) {
        watchdog_refresh();

        buffers.handleUSB();
        updateDrawBuffer(calculateInterpCoefficient());
        leds.show();

        // Optionally disable dithering by clearing our residual buffer every frame.
        if (buffers.flags & CFLAG_NO_DITHERING) {
            for (unsigned i = 0; i < CHANNELS_TOTAL; ++i)
                residual[i] = 0;
        }
    }

    // Reboot into DFU bootloader
    dfu_reboot();
}
示例#3
0
int watchdog_deinit()
{
	uchar* ctrl_addr = ( uchar* )HW_ADDR( WATCHDOG_CTRL, 0 );
	watchdog_refresh();
	*ctrl_addr = 0x00;

	return ERR_NONE;
}
示例#4
0
void read_adc24(unsigned char a, unsigned long *d)
{
   unsigned char i, m;

   /* write to communication register */

   ADC_NCS = 0;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);

   /* write zero to !WEN and one to R/!W */
   for (i=0 ; i<4 ; i++) {
      ADC_SCLK = 0;
      delay_us(OPT_DELAY);
      ADC_DIN  = (i == 1);
      delay_us(OPT_DELAY);
      ADC_SCLK = 1;
      delay_us(OPT_DELAY);
      watchdog_refresh(1);
   }

   /* register address */
   for (i=0,m=8 ; i<4 ; i++) {
      ADC_SCLK = 0;
      delay_us(OPT_DELAY);
      ADC_DIN  = (a & m) > 0;
      delay_us(OPT_DELAY);
      ADC_SCLK = 1;
      delay_us(OPT_DELAY);
      m >>= 1;
      watchdog_refresh(1);
   }

   ADC_NCS = 1;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);

   /* read from selected data register */

   ADC_NCS = 0;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);

   for (i=0,*d=0 ; i<24 ; i++) {
      *d <<= 1;
      ADC_SCLK = 0;
      delay_us(OPT_DELAY);
      delay_us(OPT_DELAY);
      *d |= ADC_DOUT;
      ADC_SCLK = 1;
      delay_us(OPT_DELAY);
      watchdog_refresh(1);
   }

   ADC_NCS = 1;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);
}
示例#5
0
void write_adc(unsigned char a, unsigned char d)
{
   unsigned char xdata i, m;

   /* write to communication register */

   ADC_NCS = 0;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);

   /* write zeros to !WEN and R/!W */
   for (i=0 ; i<4 ; i++) {
      ADC_SCLK = 0;
      delay_us(OPT_DELAY);
      ADC_DIN  = 0;
      delay_us(OPT_DELAY);
      ADC_SCLK = 1;
      delay_us(OPT_DELAY);
      watchdog_refresh(1);
   }

   /* register address */
   for (i=0,m=8 ; i<4 ; i++) {
      ADC_SCLK = 0;
      delay_us(OPT_DELAY);
      ADC_DIN  = (a & m) > 0;
      delay_us(OPT_DELAY);
      ADC_SCLK = 1;
      delay_us(OPT_DELAY);
      m >>= 1;
      watchdog_refresh(1);
   }

   ADC_NCS = 1;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);

   /* write to selected data register */

   ADC_NCS = 0;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);

   for (i=0,m=0x80 ; i<8 ; i++) {
      ADC_SCLK = 0;
      delay_us(OPT_DELAY);
      ADC_DIN  = (d & m) > 0;
      delay_us(OPT_DELAY);
      ADC_SCLK = 1;
      delay_us(OPT_DELAY);
      m >>= 1;
      watchdog_refresh(1);
   }

   ADC_NCS = 1;
   delay_us(OPT_DELAY);
   watchdog_refresh(1);
}
示例#6
0
void regulation(unsigned char channel)
{
   /* if demand value changed, remember time to avoid current 
      trip sensing for the next few seconds */
   if (chn_bits[channel] & DEMAND_CHANGED)
      t_ramp[channel] = time();

   /* only if HV on and not disabled and not ramping */
   if ((user_data[channel].control & CONTROL_HV_ON) &&
       !(user_data[channel].status & STATUS_DISABLED) &&
       (chn_bits[channel] & (RAMP_UP | RAMP_DOWN)) == 0 &&
       !(user_data[channel].status & STATUS_ILIMIT)) {
      if (user_data[channel].control & CONTROL_REGULATION) {

         u_actual[channel] = user_data[channel].u_demand;

         /* correct if difference is at least half a LSB */
         if (fabs(user_data[channel].u_demand - user_data[channel].u_meas) / DIVIDER / 2.5 * 65536 > 0.5) {

            user_data[channel].u_dac += user_data[channel].u_demand - user_data[channel].u_meas;

            /* only allow +-2V fine regulation range */
            if (user_data[channel].u_dac < user_data[channel].u_demand - 2)
               user_data[channel].u_dac = user_data[channel].u_demand - 2;

            if (user_data[channel].u_dac > user_data[channel].u_demand + 2)
               user_data[channel].u_dac = user_data[channel].u_demand + 2;

            chn_bits[channel] &= ~DEMAND_CHANGED;
         }

      } else {
         /* set voltage directly */
         if (chn_bits[channel] & DEMAND_CHANGED) {
            u_actual[channel] = user_data[channel].u_demand;
            user_data[channel].u_dac = user_data[channel].u_demand;

            chn_bits[channel] &= ~DEMAND_CHANGED;
         }
      }
   }

   /* if HV switched off, set DAC to zero */
   if (!(user_data[channel].control & CONTROL_HV_ON) &&
       (chn_bits[channel] & DEMAND_CHANGED)) {

      user_data[channel].u_dac = 0;
      u_actual[channel] = 0;
      set_hv(channel, 0);
      chn_bits[channel] &= ~DEMAND_CHANGED;
   }

   watchdog_refresh(1);
}
示例#7
0
int watchdog_init()
{
	uchar* ctrl_addr = ( uchar* )HW_ADDR( WATCHDOG_CTRL, 0 );
	watchdog_refresh();

	/* Timeout 8 seconds */
	*ctrl_addr = 0x07;
	DEBUG_PRINT( DBG_WATCHDOG, "watchdog initialized to %c\n", ( uchar* )HW_READ( WATCHDOG_CTRL, 0 ) );

	return ERR_NONE;
}
示例#8
0
void lcd_send(unsigned char *buf, unsigned char len)
{
   unsigned char idata status, i;

   for (i=0 ; i<10 ; i++) {
      lcd_sendbuf(buf, len);
      delay_us(6);
      status = lcd_io(0xFF);
      if (status == ACK)
         break;
      watchdog_refresh(0);
      delay_us(10);
   }
}
示例#9
0
void lcd_text(unsigned short x, unsigned short y, char align, char *str)
{
   unsigned char status, i, j, cs, len;

   len = strlen(str);

   for (j=0 ; j<10 ; j++) {

      lcd_io(DC1);
      cs = DC1;

      lcd_io(len+8);
      cs += len+8;

      lcd_io(ESC);
      cs += ESC;

      lcd_io('Z');
      cs += 'Z';

      lcd_io(align);
      cs += align;

      lcd_io(x & 0xFF);
      cs += (x & 0xFF);

      lcd_io(x >> 8);
      cs += (x >> 8);

      lcd_io(y & 0xFF);
      cs += (y & 0xFF);

      lcd_io(y >> 8);
      cs += (y >> 8);

      for (i=0 ; i<len+1 ; i++) {
         lcd_io(str[i]);
         cs += str[i];
      }

      lcd_io(cs);

      delay_us(6);
      status = lcd_io(0xFF);
      if (status == ACK)
         break;
      watchdog_refresh(0);
      delay_us(10);
   }
}
示例#10
0
static void dfu_reboot()
{
    // Reboot to the Fadecandy Bootloader
    boot_token = 0x74624346;

    // Short delay to allow the host to receive the response to DFU_DETACH.
    uint32_t deadline = millis() + 10;
    while (millis() < deadline) {
        watchdog_refresh();
    }

    // Detach from USB, and use the watchdog to time out a 10ms USB disconnect.
    __disable_irq();
    USB0_CONTROL = 0;
    while (1);
}
示例#11
0
void adc_read(channel, float *d)
{
   unsigned long value;
   unsigned int i, n;
   float gvalue;

   AMX0SL = channel & 0x0F;
   ADC0CF = 0xE0;               // 16 system clocks, gain 1

   n = 1 << (8 + 4);

   value = 0;
   for (i = 0; i < n; i++) {
      DISABLE_INTERRUPTS;

      ADCINT = 0;
      ADBUSY = 1;
      while (!ADCINT);          // wait until conversion ready, does NOT work with ADBUSY!

      ENABLE_INTERRUPTS;

      value += (ADC0L | (ADC0H << 8));
      watchdog_refresh();
   }

   value >>= 8;

   /* convert to volts */
   gvalue = value / 65536.0 * 2.5;

   /* external voltage divider */
   gvalue *= 0.5 * user_conf.gain_cal;

   /* convert to Ohms (15V supply, 2kOhm resistor) */
   gvalue = (2000 * gvalue) / (15 - gvalue);

   /* convert Ohms to Celsius, valid -100.100 deg., error <0.04K */
   gvalue -= 100;
   gvalue = 0.0011 * gvalue * gvalue + 2.5558 * gvalue;

   /* correct for offset */
   gvalue += user_conf.ofs_cal;

   DISABLE_INTERRUPTS;
   *d = gvalue;
   ENABLE_INTERRUPTS;
}
示例#12
0
extern "C" int main()
{
    pinMode(LED_BUILTIN, OUTPUT);
    leds.begin();

    // Announce firmware version
    serial_begin(BAUD2DIV(115200));
    serial_print("Fadecandy v" DEVICE_VER_STRING "\r\n");

    // Application main loop
    while (usb_dfu_state == DFU_appIDLE) {
        watchdog_refresh();

        // Select a different drawing loop based on our firmware config flags
        switch (buffers.flags & (CFLAG_NO_INTERPOLATION | CFLAG_NO_DITHERING)) {
            case 0:
            default:
                updateDrawBuffer_I1_D1(calculateInterpCoefficient());
                break;
            case CFLAG_NO_INTERPOLATION:
                updateDrawBuffer_I0_D1(0x10000);
                break;
            case CFLAG_NO_DITHERING:
                updateDrawBuffer_I1_D0(calculateInterpCoefficient());
                break;
            case CFLAG_NO_INTERPOLATION | CFLAG_NO_DITHERING:
                updateDrawBuffer_I0_D0(0x10000);
                break;
        }

        // Start sending the next frame over DMA
        leds.show();

        // We can switch to the next frame's buffer now.
        buffers.finalizeFrame();

        // Performance counter, for monitoring frame rate externally
        perf_frameCounter++;
    }

    // Reboot into DFU bootloader
    dfu_reboot();
}
示例#13
0
void ramp_hv(unsigned char channel)
{
   unsigned char delta;

   /* only process ramping when HV is on and not tripped */
   if ((user_data[channel].control & CONTROL_HV_ON) &&
       !(user_data[channel].status & STATUS_DISABLED)) {

      if (chn_bits[channel] & DEMAND_CHANGED) {
         /* start ramping */

         if (user_data[channel].u_demand > u_actual[channel] &&
             user_data[channel].ramp_up > 0) {
            /* ramp up */
            chn_bits[channel] |= RAMP_UP;
            chn_bits[channel] &= ~RAMP_DOWN;
            user_data[channel].status |= STATUS_RAMP_UP;
            user_data[channel].status &= ~STATUS_RAMP_DOWN;
            user_data[channel].status &= ~STATUS_RILIMIT;
            chn_bits[channel] &= ~DEMAND_CHANGED;
         }

         if (user_data[channel].u_demand < u_actual[channel] &&
             user_data[channel].ramp_down > 0) {
            /* ramp down */
            chn_bits[channel] &= ~RAMP_UP;
            chn_bits[channel] |= RAMP_DOWN;
            user_data[channel].status &= ~STATUS_RAMP_UP;
            user_data[channel].status |= STATUS_RAMP_DOWN;
            user_data[channel].status &= ~STATUS_RILIMIT;
            chn_bits[channel] &= ~DEMAND_CHANGED;
         }

         /* remember start time */
         t_ramp[channel] = time();
      }

      /* ramp up */
      if (chn_bits[channel] & RAMP_UP) {
         delta = time() - t_ramp[channel];
         if (user_data[channel].i_meas > user_data[channel].ri_limit)
            user_data[channel].status |= STATUS_RILIMIT;
         else
            user_data[channel].status &= ~STATUS_RILIMIT;

         if (delta && user_data[channel].i_meas < user_data[channel].ri_limit) {
            u_actual[channel] += (float) user_data[channel].ramp_up * delta / 100.0;
            user_data[channel].u_dac = u_actual[channel];

            if (u_actual[channel] >= user_data[channel].u_demand) {
               /* finish ramping */

               u_actual[channel] = user_data[channel].u_demand;
               user_data[channel].u_dac = u_actual[channel];
               chn_bits[channel] &= ~RAMP_UP;
               user_data[channel].status &= ~STATUS_RAMP_UP;
               user_data[channel].status &= ~STATUS_RILIMIT;
            }

            set_hv(channel, user_data[channel].u_dac);
            t_ramp[channel] = time();
         }
      }

      /* ramp down */
      if (chn_bits[channel] & RAMP_DOWN) {
         delta = time() - t_ramp[channel];
         if (delta) {
            u_actual[channel] -= (float) user_data[channel].ramp_down * delta / 100.0;
            user_data[channel].u_dac = u_actual[channel];

            /* handle trip ramping */
            if (user_data[channel].status & STATUS_ILIMIT) {
               if (u_actual[channel] <= 0) {
                  /* finish ramping */
   
                  u_actual[channel] = 0;
                  user_data[channel].u_dac = 0;
                  chn_bits[channel] &= ~RAMP_DOWN;
                  user_data[channel].status &= ~STATUS_RAMP_DOWN;
   
               }
            } else {
               if (u_actual[channel] <= user_data[channel].u_demand) {
                  /* finish ramping */
   
                  u_actual[channel] = user_data[channel].u_demand;
                  user_data[channel].u_dac = u_actual[channel];
                  chn_bits[channel] &= ~RAMP_DOWN;
                  user_data[channel].status &= ~STATUS_RAMP_DOWN;
   
               }
            }

            set_hv(channel, user_data[channel].u_dac);
            t_ramp[channel] = time();
         }
      }
   }

   watchdog_refresh(1);
}
示例#14
0
void user_loop(void)
{
   unsigned char xdata channel, i;

   /* loop over all HV channels */
   for (channel=0 ; channel<N_HV_CHN ; channel++) {

      watchdog_refresh(0);

      if ((user_data[0].control & CONTROL_IDLE) == 0) {

         /* set current limit if changed */
         if (chn_bits[channel] & CUR_LIMIT_CHANGED) {
            set_current_limit(user_data[channel].i_limit);
            chn_bits[channel] &= ~CUR_LIMIT_CHANGED;
            trip_reset = 1;
         }

         /* read back HV and current */
         read_hv(channel);
         read_current(channel);

         /* check for current trip */
         check_current(channel);

         /* do ramping and regulation */
         ramp_hv(channel);
         regulation(channel);

         /* set voltage regularly, in case DAC got HV spike */
         set_hv(channel, user_data[channel].u_dac);

      }

#ifdef HARDWARE_TRIP
      if (trip_reset) {
         reset_hardware_trip();
         trip_reset = 0;
      }
#endif

      /* if crate HV switched off, set DAC to zero */
      if (SW1) {
         for (i = 0 ; i<N_HV_CHN ; i++ ) {
            user_data[i].u_dac = 0;
            user_data[i].status |= STATUS_DISABLED;
            u_actual[i] = 0;
            set_hv(i, 0);
         }
         old_sw1 = 1;
      }
   
      /* if crate HV switched on, indicated changed demand value*/
      if (!SW1 && old_sw1) {
         for (i = 0 ; i<N_HV_CHN ; i++ ) {
            chn_bits[i] |= DEMAND_CHANGED;
            user_data[i].status &= ~STATUS_DISABLED;
         }
         old_sw1 = 0;
      }
   }

   /* reset ADC once all channels have been read */
   reset_adc();

   // read_temperature();
}
示例#15
0
extern "C" int main()
{
    uint32_t last = systick_millis_count;
    uint32_t lastRender = 0;
    uint16_t i = 0;
    uint16_t j = 0;
    uint8_t index = 0;
    uint8_t startIndex = 0;
    pinMode(LED_BUILTIN, OUTPUT);
    for (i = 0; i < LUT_TOTAL_SIZE; i++)
    {
      buffers.lutCurrent.entries[i] = defaultLUT[i] >> 1;// (i % LUT_CH_SIZE) << 7;
    }

#ifdef RAINBOW_LANTERNS
    int16_t numSteps = 64;
#endif

    leds.begin();

    rainbow10[0] = rainbow7[0] = color(0xFF, 0, 0);
    rainbow10[1] = rainbow7[1] = color(0xFF, 0xA5, 0);
    rainbow10[2] = rainbow7[2] = color(0xFF, 0xFF, 0);
    rainbow10[3] = rainbow7[3] = color(0, 0x80, 0);
    rainbow10[4] = color(0, 0xFF, 0);
    rainbow10[5] = color(0, 0xA5, 0x80);
    rainbow10[6] = rainbow7[4] = color(0, 0, 0xFF);
    rainbow10[7] = rainbow7[5] = color(0x4B, 0, 0x82);
    rainbow10[8] = rainbow7[6] = color(0xFF, 0, 0xFF);
    rainbow10[9] = color(0xEE, 0x82, 0xEE);

    buffers.flags = CFLAG_NO_ACTIVITY_LED;
    //buffers.flags |= CFLAG_LED_CONTROL;

    // Announce firmware version
    serial_begin(BAUD2DIV(115200));
    serial_print("Fadecandy v" DEVICE_VER_STRING "\r\n");

    //usb_serial_printf("test\n");

    // Application main loop
    while (usb_dfu_state == DFU_appIDLE) {
        watchdog_refresh();

        // Select a different drawing loop based on our firmware config flags
        switch (buffers.flags & (CFLAG_NO_INTERPOLATION | CFLAG_NO_DITHERING)) {
            case 0:
            default:
                updateDrawBuffer_I1_D1(calculateInterpCoefficient());
                break;
            case CFLAG_NO_INTERPOLATION:
                updateDrawBuffer_I0_D1(0x10000);
                break;
            case CFLAG_NO_DITHERING:
                updateDrawBuffer_I1_D0(calculateInterpCoefficient());
                break;
            case CFLAG_NO_INTERPOLATION | CFLAG_NO_DITHERING:
                updateDrawBuffer_I0_D0(0x10000);
                break;
        }

        //buffers.flags |= CFLAG_NO_ACTIVITY_LED;
        // Start sending the next frame over DMA
        leds.show();

        if ((systick_millis_count - last) > 500)
        {
            //buffers.flags ^= CFLAG_LED_CONTROL;

            last = systick_millis_count;
        }

        #ifdef RAINBOW_CIRCLE
        if ((systick_millis_count - lastRender) > 500)
        {
          buffers.flags ^= CFLAG_LED_CONTROL;
          lastRender = systick_millis_count;
          index = startIndex;

          for (i = 0; i < 52/*32*/; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 7 + i);
            uint32_t color = rainbow7[index];

            pixel[0] = RED(color);
            pixel[1] = GREEN(color);
            pixel[2] = BLUE(color);

            index = (index + 1) % 7;
          }

          for (i = 0; i < 20; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 6 + i);
            uint32_t color = rainbow7[index];

            pixel[0] = RED(color);
            pixel[1] = GREEN(color);
            pixel[2] = BLUE(color);

            index = (index + 1) % 7;
          }

          startIndex = (startIndex + 1) % 7;

          buffers.finalizeFramebuffer();
        }
        #endif

#ifdef RAINBOW_TOPHAT
        (void)j;
        if ((systick_millis_count - lastRender) > 500)
        {
          buffers.flags ^= CFLAG_LED_CONTROL;
          lastRender = systick_millis_count;
          index = startIndex;

          for (i = 0; i < 52/*32*/; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 7 + i);
            uint32_t color = rainbow7[index];

            pixel[0] = RED(color);
            pixel[1] = GREEN(color);
            pixel[2] = BLUE(color);
            if (i>0 && i % 5 == 0)
            {
              index = (index + 1) % 7;
            }
          }

          for (i = 0; i < 20; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 6 + i);
            uint32_t color = rainbow7[index];

            pixel[0] = RED(color);
            pixel[1] = GREEN(color);
            pixel[2] = BLUE(color);

            index = (index + 1) % 7;
          }

          startIndex = (startIndex + 1) % 7;

          buffers.finalizeFramebuffer();
        }
#endif

#ifdef RAINBOW_LANTERNS
        /*(void)j;
        (void)index;
        (void)startIndex;
        if ((systick_millis_count - lastRender) > 500)
        {
          buffers.flags ^= CFLAG_LED_CONTROL;
          lastRender = systick_millis_count;

          for (i = 0; i < 20; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 7 + i);
            int16_t direction = directions[i] < 0 ? -1 : 1;
            uint32_t color1 = rainbow7[indexes[i]];
            int16_t index2 = indexes[i] + direction;
            if (index2 < 0)
            {
              index2 = 6;
            }
            else if (index2 >= 7)
            {
              index2 = 0;
            }
            uint32_t color2 = rainbow7[index2];

            int32_t reddiff = RED(color2) - RED(color1);
            int32_t bluediff = BLUE(color2) - BLUE(color1);
            int32_t greendiff = GREEN(color2) - BLUE(color1);

            reddiff *= steps[i];
            reddiff /= numSteps;
            bluediff *= steps[i];
            bluediff /= numSteps;
            greendiff *= steps[i];
            greendiff /= numSteps;

            pixel[0] = RED(color1) + reddiff;
            pixel[1] = GREEN(color1) + greendiff;
            pixel[2] = BLUE(color1) + bluediff;

            steps[i] += abs(directions[i]);

            if (steps[i] >= numSteps)
            {
              steps[i] = 0;
              indexes[i] = index2;
            }
          }

          buffers.finalizeFramebuffer();
        }*/
        (void)j;
        (void)numSteps;
        if ((systick_millis_count - lastRender) > 5000)
        {
          buffers.flags ^= CFLAG_LED_CONTROL;
          lastRender = systick_millis_count;
          index = startIndex;

          for (i = 0; i < 20/*32*/; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 7 + i);
            uint32_t color = rainbow7[index];

            pixel[0] = RED(color);
            pixel[1] = GREEN(color);
            pixel[2] = BLUE(color);
            if (i>0 && i % 2 == 0)
            {
              index = (index + 1) % 7;
            }
          }

          for (i = 0; i < 20; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 6 + i);
            uint32_t color = rainbow7[index];

            pixel[0] = RED(color);
            pixel[1] = GREEN(color);
            pixel[2] = BLUE(color);

            index = (index + 1) % 7;
          }

          startIndex = (startIndex + 1) % 7;

          buffers.finalizeFramebuffer();
        }
#endif

#ifdef PARASOL
        if ((systick_millis_count - lastRender) > 500)
        {
          buffers.flags ^= CFLAG_LED_CONTROL;
          lastRender = systick_millis_count;
          index = startIndex;

          for (i = 0; i < 8; i++)
          {
            for (j = 0; j < 3; j++)
            {
              uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * i + j);
              uint32_t color = rainbow7[index];

              pixel[0] = RED(color);
              pixel[1] = GREEN(color);
              pixel[2] = BLUE(color);
            }

            index = (index + 1) % 7;
          }

          startIndex = (startIndex + 1) % 7;

          buffers.finalizeFramebuffer();
        }
#endif

        #ifdef SMOOTH_RAINBOW
        (void)startIndex;
        (void)j;
        if ((systick_millis_count - lastRender) > 30)
        {
          lastRender = systick_millis_count;
          uint32_t ledIndex = 0;

          if (index >= 16)
          {
            buffers.flags ^= CFLAG_LED_CONTROL;
            index = 0;
          }

          index++;

          float color1[3];
          float color2[3];
          
          for (i = 0; i < 32; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 7 + i);

            pixel[0] = 0xFF;
            pixel[1] = 0;
            pixel[2] = 0;
            float scaled = ledIndex / 44.0f;
            //fix16_t noise = 32768; (void)scaled;
            float noise = .5f + noise2(scaled, time);
            //float noise = .5f + fbm_noise3(scaled, time, .5f, 4, .25f, 2.0f);
            noise = fmax(fmin(1, noise), 0);
            float mult = 9 * noise;

            float index1 = floor(mult);
            float index2 = ceil(mult);
            float percent = mult - index1;
            uint32_t color = rainbow10[(int)index1];
            color1[0] = RED(color);
            color1[1] = GREEN(color);
            color1[2] = BLUE(color);

            color = rainbow10[(int)index2];
            color2[0] = RED(color);
            color2[1] = GREEN(color);
            color2[2] = BLUE(color);

            pixel[0] = (uint8_t)((int)(color1[0] + ((color2[0] - color1[0]) * percent)) & 0xFF);
            pixel[1] = (uint8_t)((int)(color1[1] + ((color2[1] - color1[1]) * percent)) & 0xFF);
            pixel[2] = (uint8_t)((int)(color1[2] + ((color2[2] - color1[2]) * percent)) & 0xFF);

            ledIndex++;
          }
          /*
          for (i = 0; i < 12; i++)
          {
            uint8_t* pixel = buffers.fbNew->pixel(LEDS_PER_STRIP * 6 + i);

            pixel[0] = 0xFF;
            pixel[1] = 0;
            pixel[2] = 0;
            float scaled = ledIndex / 44.0f;
            (void)scaled;
            float noise = 32768;
              //noise2(scaled, time);
            //fix16_t noise = 32768 + noise2(scaled, time);
            //fix16_t noise = 32768 + fbm_noise3(scaled, time, 0, 4, 16384, 131072);
            noise = fmax(fmin(noise, 1), 0);
            float mult = 9 * noise;
            float index1 = floor(mult);
            float index2 = ceil(mult);
            float percent = mult - index1;
            (void)index2;
            (void)percent;
            uint32_t color = rainbow10[1];// fix16_to_int(index1)];
            color1[0] = RED(color);
            color1[1] = GREEN(color);
            color1[2] = BLUE(color);

            color = rainbow10[2];// fix16_to_int(index2)];
            color2[0] = RED(color);
            color2[1] = GREEN(color);
            color2[2] = BLUE(color);

            pixel[0] = (uint8_t)((int)(color1[0] + ((color2[0] - color1[0]) * percent)) & 0xFF);
            pixel[1] = (uint8_t)((int)(color1[1] + ((color2[1] - color1[1]) * percent)) & 0xFF);
            pixel[2] = (uint8_t)((int)(color1[2] + ((color2[2] - color1[2]) * percent)) & 0xFF);

            ledIndex++;
          } */

          time = (time + timestep);

          buffers.finalizeFramebuffer();
        }
        #endif

        // We can switch to the next frame's buffer now.
        buffers.finalizeFrame();

        // Performance counter, for monitoring frame rate externally
        perf_frameCounter++;
    }

    // Reboot into DFU bootloader
    dfu_reboot();
}