Martin Johnson / neopixels

Dependencies:   STM32F3-Discovery

Revision:
0:d89511b21e3d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/neopixel.c	Wed May 25 23:54:30 2016 +0000
@@ -0,0 +1,506 @@
+
+#include <stm32f30x.h>
+//#include <stm32f30x_misc.h>
+//#define ARM_MATH_CM4
+#include <math.h>
+#include "stm32f3_discovery_lsm303dlhc.h"
+#include <stdlib.h>
+
+#define WS2812_GPIO                     GPIOB
+#define WS2812_GPIO_AHB_PERIPHERAL      RCC_AHBPeriph_GPIOB
+#define WS2812_GPIO_AF                  GPIO_AF_1
+#define WS2812_PIN                      GPIO_Pin_8 // TIM16_CH1
+#define WS2812_PIN_SOURCE               GPIO_PinSource8
+#define WS2812_TIMER                    TIM16
+#define WS2812_TIMER_APB2_PERIPHERAL    RCC_APB2Periph_TIM16
+#define WS2812_DMA_CHANNEL              DMA1_Channel3
+#define WS2812_IRQ                      DMA1_Channel3_IRQn
+#define WS2812_DMA_TC_FLAG              DMA1_FLAG_TC3
+
+#define PI 3.1415926f
+
+#define WS2812_LED_STRIP_LENGTH 60
+#define WS2812_BITS_PER_LED 24
+#define WS2812_DELAY_BUFFER_LENGTH 42 // for 50us delay
+
+#define BIT_COMPARE_1 17 // timer compare value for logical 1
+#define BIT_COMPARE_0 9  // timer compare value for logical 0
+#define WS2812_DATA_BUFFER_SIZE (WS2812_BITS_PER_LED * WS2812_LED_STRIP_LENGTH)
+
+#define WS2812_DMA_BUFFER_SIZE (WS2812_DATA_BUFFER_SIZE + WS2812_DELAY_BUFFER_LENGTH)   // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes)
+
+static volatile uint8_t ledStripDMABuffer[WS2812_DMA_BUFFER_SIZE];
+
+//static volatile uint8_t rgbData[WS2812_LED_STRIP_LENGTH*3];
+
+static volatile uint8_t WS2812LedDataTransferInProgress = 0;
+static uint16_t dmaBufferOffset;
+static int16_t ledIndex;
+
+volatile  unsigned	sysTiming;
+volatile  unsigned  sysTicks = 0;
+
+int sysInitSystemTimer(void) {
+
+	if (SysTick_Config((SystemCoreClock / 1000) -1 )) {
+		return(0);
+	}
+	return(1);
+}
+void sysDelayMs(unsigned dly) {
+
+	sysTiming = dly;
+
+	while (sysTiming > 0) __wfi();
+
+}
+void SysTick_Handler(void) {
+        sysTicks++;
+        if (sysTiming > 0) --sysTiming; 
+}
+
+void AccelerometerConfig(void)
+{
+  LSM303DLHCMag_InitTypeDef LSM303DLHC_InitStructure;
+  LSM303DLHCAcc_InitTypeDef LSM303DLHCAcc_InitStructure;
+  LSM303DLHCAcc_FilterConfigTypeDef LSM303DLHCFilter_InitStructure;
+  
+  /* Configure MEMS magnetometer main parameters: temp, working mode, full Scale and Data rate */
+  LSM303DLHC_InitStructure.Temperature_Sensor = LSM303DLHC_TEMPSENSOR_DISABLE;
+  LSM303DLHC_InitStructure.MagOutput_DataRate =LSM303DLHC_ODR_30_HZ ;
+  LSM303DLHC_InitStructure.MagFull_Scale = LSM303DLHC_FS_8_1_GA;
+  LSM303DLHC_InitStructure.Working_Mode = LSM303DLHC_CONTINUOS_CONVERSION;
+  LSM303DLHC_MagInit(&LSM303DLHC_InitStructure);
+  
+   /* Fill the accelerometer structure */
+  LSM303DLHCAcc_InitStructure.Power_Mode = LSM303DLHC_NORMAL_MODE;
+  LSM303DLHCAcc_InitStructure.AccOutput_DataRate = LSM303DLHC_ODR_50_HZ;
+  LSM303DLHCAcc_InitStructure.Axes_Enable= LSM303DLHC_AXES_ENABLE;
+  LSM303DLHCAcc_InitStructure.AccFull_Scale = LSM303DLHC_FULLSCALE_2G;
+  LSM303DLHCAcc_InitStructure.BlockData_Update = LSM303DLHC_BlockUpdate_Continous;
+  LSM303DLHCAcc_InitStructure.Endianness=LSM303DLHC_BLE_LSB;
+  LSM303DLHCAcc_InitStructure.High_Resolution=LSM303DLHC_HR_ENABLE;
+  /* Configure the accelerometer main parameters */
+  LSM303DLHC_AccInit(&LSM303DLHCAcc_InitStructure);
+  
+  /* Fill the accelerometer LPF structure */
+  LSM303DLHCFilter_InitStructure.HighPassFilter_Mode_Selection =LSM303DLHC_HPM_NORMAL_MODE;
+  LSM303DLHCFilter_InitStructure.HighPassFilter_CutOff_Frequency = LSM303DLHC_HPFCF_16;
+  LSM303DLHCFilter_InitStructure.HighPassFilter_AOI1 = LSM303DLHC_HPF_AOI1_DISABLE;
+  LSM303DLHCFilter_InitStructure.HighPassFilter_AOI2 = LSM303DLHC_HPF_AOI2_DISABLE;
+
+  /* Configure the accelerometer LPF main parameters */
+  LSM303DLHC_AccFilterConfig(&LSM303DLHCFilter_InitStructure);
+}
+
+void ReadAccelerometer(float * data)
+{
+  uint8_t buffer[6];
+  
+  LSM303DLHC_Read(ACC_I2C_ADDRESS, LSM303DLHC_OUT_X_L_A, buffer, 6);
+  
+  for(int i=0; i<3; i++) {
+	data[i]=(float)((int16_t)((uint16_t)buffer[2*i+1] << 8) + buffer[2*i])/16;
+  }
+}
+
+void ReadMagnetometer (float* pfData)
+{
+  static uint8_t buffer[6] = {0};
+  uint8_t CTRLB = 0;
+  uint16_t Magn_Sensitivity_XY = 0, Magn_Sensitivity_Z = 0;
+  uint8_t i =0;
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_CRB_REG_M, &CTRLB, 1);
+  
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_X_H_M, buffer, 1);
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_X_L_M, buffer+1, 1);
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Y_H_M, buffer+2, 1);
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Y_L_M, buffer+3, 1);
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Z_H_M, buffer+4, 1);
+  LSM303DLHC_Read(MAG_I2C_ADDRESS, LSM303DLHC_OUT_Z_L_M, buffer+5, 1);
+  /* Switch the sensitivity set in the CRTLB*/
+  switch(CTRLB & 0xE0)
+  {
+  case LSM303DLHC_FS_1_3_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_1_3Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_1_3Ga;
+    break;
+  case LSM303DLHC_FS_1_9_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_1_9Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_1_9Ga;
+    break;
+  case LSM303DLHC_FS_2_5_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_2_5Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_2_5Ga;
+    break;
+  case LSM303DLHC_FS_4_0_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_4Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_4Ga;
+    break;
+  case LSM303DLHC_FS_4_7_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_4_7Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_4_7Ga;
+    break;
+  case LSM303DLHC_FS_5_6_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_5_6Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_5_6Ga;
+    break;
+  case LSM303DLHC_FS_8_1_GA:
+    Magn_Sensitivity_XY = LSM303DLHC_M_SENSITIVITY_XY_8_1Ga;
+    Magn_Sensitivity_Z = LSM303DLHC_M_SENSITIVITY_Z_8_1Ga;
+    break;
+  }
+  
+  for(i=0; i<2; i++)
+  {
+    pfData[i]=(float)((int16_t)(((uint16_t)buffer[2*i] << 8) + buffer[2*i+1])*1000)/Magn_Sensitivity_XY;
+  }
+  pfData[2]=(float)((int16_t)(((uint16_t)buffer[4] << 8) + buffer[5])*1000)/Magn_Sensitivity_Z;
+}
+
+void GPIO_init(void) {
+    GPIO_InitTypeDef GPIO_InitStructure;
+    // GPIOA Periph clock enable
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
+    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOE, ENABLE);
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
+    RCC_APB2PeriphClockCmd(WS2812_TIMER_APB2_PERIPHERAL, ENABLE);
+
+    sysInitSystemTimer();
+    /* Configuration alternate function push-pull */
+    GPIO_StructInit(&GPIO_InitStructure);
+    GPIO_InitStructure.GPIO_Pin = WS2812_PIN;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
+    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_Init(WS2812_GPIO, &GPIO_InitStructure);
+
+    GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_1); // pb8 is tim16 ch1
+
+    GPIO_InitStructure.GPIO_Pin =
+            GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 |
+            GPIO_Pin_14 | GPIO_Pin_15;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
+    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
+    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_Init(GPIOE, &GPIO_InitStructure);
+    
+    GPIO_StructInit(&GPIO_InitStructure);
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
+    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_Init(GPIOA, &GPIO_InitStructure);
+    
+
+       GPIOE->ODR ^= 0x100;
+}
+
+void TIM_init(void)
+{
+	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+	TIM_OCInitTypeDef TIM_OCInitStructure;
+//	NVIC_InitTypeDef NVIC_InitStructure;
+	uint16_t PrescalerValue;
+
+	PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
+	/* Time base configuration */
+	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
+	TIM_TimeBaseStructure.TIM_Period = 29; // 800kHz
+	TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
+	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
+	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+	TIM_TimeBaseInit(WS2812_TIMER, &TIM_TimeBaseStructure);
+	
+   /* PWM1 Mode configuration */
+    TIM_OCStructInit(&TIM_OCInitStructure);
+    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
+    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
+    TIM_OCInitStructure.TIM_Pulse = 0;
+    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
+    TIM_OC1Init(WS2812_TIMER, &TIM_OCInitStructure);
+    TIM_OC1PreloadConfig(WS2812_TIMER, TIM_OCPreload_Enable);
+    TIM_CtrlPWMOutputs(WS2812_TIMER, ENABLE);
+}
+
+void DMA_init(void) {
+    DMA_InitTypeDef DMA_InitStructure;
+    /* configure DMA */
+    /* DMA clock enable */
+    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
+    /* DMA Channel Config */
+    DMA_DeInit(WS2812_DMA_CHANNEL);
+    DMA_StructInit(&DMA_InitStructure);
+    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) & WS2812_TIMER->CCR1;
+    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) ledStripDMABuffer;
+    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
+    DMA_InitStructure.DMA_BufferSize = WS2812_DMA_BUFFER_SIZE;
+    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
+    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
+    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
+    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
+    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
+    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
+    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
+    DMA_Init(WS2812_DMA_CHANNEL, &DMA_InitStructure);
+    TIM_DMACmd(WS2812_TIMER, TIM_DMA_CC1, ENABLE);
+    DMA_ITConfig(WS2812_DMA_CHANNEL, DMA_IT_TC, ENABLE);
+    NVIC_InitTypeDef NVIC_InitStructure;
+    NVIC_InitStructure.NVIC_IRQChannel = WS2812_IRQ;
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
+    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+    NVIC_Init(&NVIC_InitStructure);
+}
+
+void WS2812LedStripDMAEnable(void) {
+    DMA_SetCurrDataCounter(WS2812_DMA_CHANNEL,
+                           WS2812_DMA_BUFFER_SIZE);  // load number of bytes to be transferred
+    TIM_SetCounter(WS2812_TIMER, 0);
+    TIM_Cmd(WS2812_TIMER, ENABLE);
+    DMA_Cmd(WS2812_DMA_CHANNEL, ENABLE);
+}
+
+ void DMA1_Channel3_IRQHandler(void) {
+//    GPIOE->ODR ^= 0x1000;
+    if (DMA_GetFlagStatus(WS2812_DMA_TC_FLAG)) {
+        WS2812LedDataTransferInProgress = 0;
+        DMA_Cmd(WS2812_DMA_CHANNEL, DISABLE);
+        DMA_ClearFlag(WS2812_DMA_TC_FLAG);
+    }
+}
+
+void updateLEDDMABuffer(uint8_t componentValue) {
+    uint8_t bitIndex;
+
+    for (bitIndex = 0; bitIndex < 8; bitIndex++) {
+        if ((componentValue << bitIndex) &
+            0x80)    // data sent MSB first, j = 0 is MSB j = 7 is LSB
+        {
+            ledStripDMABuffer[dmaBufferOffset] = BIT_COMPARE_1;
+        }
+        else {
+            ledStripDMABuffer[dmaBufferOffset] = BIT_COMPARE_0;   // compare value for logical 0
+        }
+        dmaBufferOffset++;
+    }
+}
+
+typedef struct  {
+    uint8_t red;
+    uint8_t green;
+    uint8_t blue;
+} rgb_struct;
+
+static volatile rgb_struct rgbData[WS2812_LED_STRIP_LENGTH];
+
+void WS2812UpdateStrip(void) {
+    static uint32_t waitCounter = 0;
+
+    // wait until previous transfer completes
+    while (WS2812LedDataTransferInProgress) {
+        waitCounter++;
+    }
+
+    dmaBufferOffset = 0;                // reset buffer memory index
+    ledIndex = 0;                       // reset led index
+
+    // fill transmit buffer with correct compare values to achieve
+    // correct pulse widths according to color values
+    while (ledIndex < WS2812_LED_STRIP_LENGTH) {
+        updateLEDDMABuffer(rgbData[ledIndex].green);
+        updateLEDDMABuffer(rgbData[ledIndex].red);
+        updateLEDDMABuffer(rgbData[ledIndex++].blue);
+    }
+
+    WS2812LedDataTransferInProgress = 1;
+    WS2812LedStripDMAEnable();
+}
+
+extern volatile unsigned             sysTicks;
+int rndseed=0;
+/*
+void srand(int i) {
+    rndseed = i;
+}
+
+
+int rand() {
+    return (((rndseed = rndseed * 214013L + 2531011L) >> 16) &
+            0x7fff);
+}
+*/
+
+void WS2812LedStripInit(void) {
+    int i;
+    for (i = 0; i < WS2812_DMA_BUFFER_SIZE; i++)
+        ledStripDMABuffer[i] = 0;
+    WS2812UpdateStrip();
+}
+static  float           AccBuffer[3] = {0.0f};
+static  float           MagBuffer[3] = {0.0f};
+
+//extern float arm_sqrt_f32(float f);
+int getheading() {
+    /* Read Compass data */
+    ReadMagnetometer(MagBuffer);
+    ReadAccelerometer(AccBuffer);
+    int i;
+    float fNormAcc, fSinRoll, fCosRoll, fSinPitch, fCosPitch = 0.0f, RollAng = 0.0f, PitchAng = 0.0f;
+    float fTiltedX, fTiltedY = 0.0f;
+    float HeadingValue;
+
+    for (i = 0; i < 3; i++)
+        AccBuffer[i] /= 100.0f;
+
+    fNormAcc = sqrtf((AccBuffer[0] * AccBuffer[0]) + (AccBuffer[1] * AccBuffer[1]) +
+                    (AccBuffer[2] * AccBuffer[2]));
+
+    fSinRoll = -AccBuffer[1] / fNormAcc;
+    fCosRoll = sqrtf(1.0f - (fSinRoll * fSinRoll));
+    fSinPitch = AccBuffer[0] / fNormAcc;
+    fCosPitch = sqrtf(1.0f - (fSinPitch * fSinPitch));
+    if (fSinRoll > 0) {
+        if (fCosRoll > 0) {
+            RollAng = acos(fCosRoll) * 180 / PI;
+        }
+        else {
+            RollAng = acos(fCosRoll) * 180 / PI + 180;
+        }
+    }
+    else {
+        if (fCosRoll > 0) {
+            RollAng = acos(fCosRoll) * 180 / PI + 360;
+        }
+        else {
+            RollAng = acos(fCosRoll) * 180 / PI + 180;
+        }
+    }
+    if (fSinPitch > 0) {
+        if (fCosPitch > 0) {
+            PitchAng = acos(fCosPitch) * 180 / PI;
+        }
+        else {
+            PitchAng = acos(fCosPitch) * 180 / PI + 180;
+        }
+    }
+    else {
+        if (fCosPitch > 0) {
+            PitchAng = acos(fCosPitch) * 180 / PI + 360;
+        }
+        else {
+            PitchAng = acos(fCosPitch) * 180 / PI + 180;
+        }
+    }
+
+    if (RollAng >= 360) {
+        RollAng = RollAng - 360;
+    }
+
+    if (PitchAng >= 360) {
+        PitchAng = PitchAng - 360;
+    }
+
+    fTiltedX = MagBuffer[0] * fCosPitch + MagBuffer[2] * fSinPitch;
+    fTiltedY = MagBuffer[0] * fSinRoll * fSinPitch + MagBuffer[1] * fCosRoll -
+               MagBuffer[1] * fSinRoll * fCosPitch;
+
+//    fTiltedX=fTiltedX/sqrt(fTiltedX*fTiltedX+fTiltedY*fTiltedY);
+    HeadingValue = (float) ((atan2f( (float)fTiltedY, (float)fTiltedX)) * 180) / PI;
+
+    if (HeadingValue < 0) {
+        HeadingValue = HeadingValue + 360;
+    }
+    return HeadingValue;
+
+}
+
+int main(void) {
+    uint8_t i = 0;
+    int j=0;
+    int delay=2000;
+    int dch=-1;
+    int dir=1;
+    int btn=0;
+    uint32_t rgb = 0x0ff0000ff;
+    GPIO_init();
+    GPIOE->ODR ^= 0x100;
+    DMA_init();
+    GPIOE->ODR ^= 0x200;
+    TIM_init();
+    AccelerometerConfig();
+
+    WS2812LedDataTransferInProgress = 0;
+    WS2812LedStripInit();
+    btn=GPIOA->IDR;
+    if((GPIOA->IDR & 1)==1) {
+        // a giant compass!
+        while (1) {
+            int heading = getheading();
+            int led = (heading * WS2812_LED_STRIP_LENGTH) / 360;
+            int next = (led + 1) % WS2812_LED_STRIP_LENGTH;
+            int v2 = (heading - (led * 360) / WS2812_LED_STRIP_LENGTH) * 10;
+            int v1 = 225 - v2;
+            
+            rgbData[led].red = v1;
+            rgbData[next].red = v2;
+
+            WS2812UpdateStrip();
+            // wait 5ms
+            sysDelayMs(15);
+            rgbData[led].red = 0;
+            rgbData[next].red = 0;
+
+        }
+    }
+    while (1) { // flashing lights moving along the strip
+        rgbData[j].red = (rgb & 255); // green
+        rgbData[j].green = (rgb >> 8) & 255; // red
+        rgbData[j].blue = (rgb >> 16) & 255; // blue
+
+		int NLIGHTS=4;
+		i=j;
+		for(int k=1;k<NLIGHTS;k++) {
+         	i=(i+WS2812_LED_STRIP_LENGTH/NLIGHTS)%WS2812_LED_STRIP_LENGTH;
+	        rgbData[i].red = (rgb & 255); // green
+	        rgbData[i].green = (rgb >> 8) & 255; // red
+	        rgbData[i].blue = (rgb >> 16) & 255; // blue
+        }
+
+        WS2812UpdateStrip();
+        sysDelayMs(delay/100);
+        if((GPIOA->IDR & 1)==1 && btn==0)
+            dir=-dir;
+        btn=(GPIOA->IDR & 1);
+        delay=delay+dch;
+        if(delay<500 || delay>3000)
+            dch=-dch;
+        for(int k=0;k<WS2812_LED_STRIP_LENGTH;k++) {
+        	rgbData[k].red = 0;
+        	rgbData[k].green = 0;
+        	rgbData[k].blue = 0;
+        }
+
+        ReadAccelerometer(AccBuffer);
+        int x=(int)AccBuffer[0];
+        int y=(int)AccBuffer[1];
+        int z=(int)AccBuffer[2];
+
+        delay=10000-abs(y)*20;
+        if(delay<0) delay=0;
+        if(y<0)
+            dir=1;
+        else
+            dir=-1;
+
+        j=(j+dir+WS2812_LED_STRIP_LENGTH)%WS2812_LED_STRIP_LENGTH;
+  
+        rgb=(rgb<<1) /*^ (rand()&1 & rand()&1) ; */| (rgb>>24);
+
+    }
+}
+
+