16x16 square of neopixels for stm32f3 discovery board
Dependencies: STM32F3-Discovery-minimal
Fork of neopixels by
neopixel.c
- Committer:
- MartinJohnson
- Date:
- 2016-05-25
- Revision:
- 0:d89511b21e3d
- Child:
- 1:6ed7aa3c8efa
File content as of revision 0:d89511b21e3d:
#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); } }