78-WS2812-Library (STM32F4)
78-WS2812-Library (STM32F4)
//-------------------------------------------------------------- // File : stm32_ub_ws2812.h //-------------------------------------------------------------- //-------------------------------------------------------------- #ifndef __STM32F4_UB_WS2812_H #define __STM32F4_UB_WS2812_H //-------------------------------------------------------------- // Includes //-------------------------------------------------------------- #include "stm32f4xx.h" #include "stm32f4xx_gpio.h" #include "stm32f4xx_rcc.h" #include "stm32f4xx_tim.h" #include "stm32f4xx_dma.h" #include "misc.h" //-------------------------------------------------------------- // Anzahl der WS2812-LEDs (1...n) in den einzelnen Ketten // CPU -> LED_1 -> LED_2 -> LED_3 -> LED_n // // falls ein Channel nicht benutzt wird => laenge auf 0 setzen //-------------------------------------------------------------- #define WS2812_LED_CH1_ANZ 5 // [CH1 an PC6] LED-Kette mit 5 LEDs #define WS2812_LED_CH2_ANZ 0 // [CH2 an PB5] CH2 wird nicht benutzt #define WS2812_LED_CH3_ANZ 0 // [CH3 an PB0] CH3 wird nicht benutzt #define WS2812_LED_CH4_ANZ 0 // [CH4 an PB1] CH4 wird nicht benutzt #define WS2812_LED_MAX_ANZ 5 // anzahl der LEDs in der laengsten Kette //-------------------------------------------------------------- // check der laengenangaben //-------------------------------------------------------------- #if WS2812_LED_CH1_ANZ>WS2812_LED_MAX_ANZ #error wrong len #endif #if WS2812_LED_CH2_ANZ>WS2812_LED_MAX_ANZ #error wrong len #endif #if WS2812_LED_CH3_ANZ>WS2812_LED_MAX_ANZ #error wrong len #endif #if WS2812_LED_CH4_ANZ>WS2812_LED_MAX_ANZ #error wrong len #endif #if (WS2812_LED_MAX_ANZ>WS2812_LED_CH1_ANZ) && (WS2812_LED_MAX_ANZ>WS2812_LED_CH2_ANZ) #if (WS2812_LED_MAX_ANZ>WS2812_LED_CH3_ANZ) && (WS2812_LED_MAX_ANZ>WS2812_LED_CH4_ANZ) #error wrong len #endif #endif //-------------------------------------------------------------- // benutzer Timer fuer das Daten-Signal => TIM3 //-------------------------------------------------------------- #define WS2812_TIM_CLOCK RCC_APB1Periph_TIM3 #define WS2812_TIM TIM3 #define WS2812_TIM_AF GPIO_AF_TIM3 #define WS2812_TIM_CH1 1 #define WS2812_TIM_CCR_REG1 TIM3->CCR1 #define WS2812_TIM_DMA_TRG1 TIM_DMA_CC1 #define WS2812_TIM_CH2 2 #define WS2812_TIM_CCR_REG2 TIM3->CCR2 #define WS2812_TIM_DMA_TRG2 TIM_DMA_CC2 #define WS2812_TIM_CH3 3 #define WS2812_TIM_CCR_REG3 TIM3->CCR3 #define WS2812_TIM_DMA_TRG3 TIM_DMA_CC3 #define WS2812_TIM_CH4 4 #define WS2812_TIM_CCR_REG4 TIM3->CCR4 #define WS2812_TIM_DMA_TRG4 TIM_DMA_CC4 //-------------------------------------------------------------- // GPIO-Pins (CH1...CH4) fuer Data-OUT // // moegliche Pinbelegungen (bei TIM3) // CH1 : [PA6, PB4, PC6] // CH2 : [PA7, PB5, PC7] // CH3 : [PB0, PC8] // CH4 : [PB1, PC9] //-------------------------------------------------------------- #define WS2812_CH1_CLOCK RCC_AHB1Periph_GPIOC #define WS2812_CH1_PORT GPIOC #define WS2812_CH1_PIN GPIO_Pin_6 #define WS2812_CH1_SOURCE GPIO_PinSource6 #define WS2812_CH2_CLOCK RCC_AHB1Periph_GPIOB #define WS2812_CH2_PORT GPIOB #define WS2812_CH2_PIN GPIO_Pin_5 #define WS2812_CH2_SOURCE GPIO_PinSource5 #define WS2812_CH3_CLOCK RCC_AHB1Periph_GPIOB #define WS2812_CH3_PORT GPIOB #define WS2812_CH3_PIN GPIO_Pin_0 #define WS2812_CH3_SOURCE GPIO_PinSource0 #define WS2812_CH4_CLOCK RCC_AHB1Periph_GPIOB #define WS2812_CH4_PORT GPIOB #define WS2812_CH4_PIN GPIO_Pin_1 #define WS2812_CH4_SOURCE GPIO_PinSource1 //-------------------------------------------------------------- // benutzer DMA // => TIM3-CC1 => DMA1, Channel5, Stream4 // => TIM3-CC2 => DMA1, Channel5, Stream5 // => TIM3-CC3 => DMA1, Channel5, Stream7 // => TIM3-CC4 => DMA1, Channel5, Stream2 // (siehe Seite 216+217 vom Referenz Manual) //-------------------------------------------------------------- #define WS2812_DMA_CLOCK RCC_AHB1Periph_DMA1 #define WS2812_DMA_CH1_STREAM DMA1_Stream4 #define WS2812_DMA_CH1_CHANNEL DMA_Channel_5 #define WS2812_DMA_CH2_STREAM DMA1_Stream5 #define WS2812_DMA_CH2_CHANNEL DMA_Channel_5 #define WS2812_DMA_CH3_STREAM DMA1_Stream7 #define WS2812_DMA_CH3_CHANNEL DMA_Channel_5 #define WS2812_DMA_CH4_STREAM DMA1_Stream2 #define WS2812_DMA_CH4_CHANNEL DMA_Channel_5 //-------------------------------------------------------------- // Transfer-Complete Interrupt // CC1 => DMA1, Stream4 // CC2 => DMA1, Stream5 // CC3 => DMA1, Stream7 // CC4 => DMA1, Stream2 //-------------------------------------------------------------- #define WS2812_DMA_CH1_IRQn DMA1_Stream4_IRQn #define WS2812_DMA_CH1_ISR DMA1_Stream4_IRQHandler #define WS2812_DMA_CH1_IRQ_FLAG DMA_IT_TCIF4 #define WS2812_DMA_CH2_IRQn DMA1_Stream5_IRQn #define WS2812_DMA_CH2_ISR DMA1_Stream5_IRQHandler #define WS2812_DMA_CH2_IRQ_FLAG DMA_IT_TCIF5 #define WS2812_DMA_CH3_IRQn DMA1_Stream7_IRQn #define WS2812_DMA_CH3_ISR DMA1_Stream7_IRQHandler #define WS2812_DMA_CH3_IRQ_FLAG DMA_IT_TCIF7 #define WS2812_DMA_CH4_IRQn DMA1_Stream2_IRQn #define WS2812_DMA_CH4_ISR DMA1_Stream2_IRQHandler #define WS2812_DMA_CH4_IRQ_FLAG DMA_IT_TCIF2 //-------------------------------------------------------------- // RGB LED Farbdefinition (3 x 8bit) //-------------------------------------------------------------- typedef struct { uint8_t red; // 0...255 (als PWM-Wert) uint8_t green; // 0...255 (als PWM-Wert) uint8_t blue; // 0...255 (als PWM-Wert) } WS2812_RGB_t; //-------------------------------------------------------------- // HSV LED Farbdefinition //-------------------------------------------------------------- typedef struct { uint16_t h; // 0...359 (in Grad, 0=R, 120=G, 240=B) uint8_t s; // 0...100 (in Prozent) uint8_t v; // 0...100 (in Prozent) } WS2812_HSV_t; //-------------------------------------------------------------- // Globale Buffer fuer die Farben (als RGB-Wert) //-------------------------------------------------------------- #if WS2812_LED_CH1_ANZ>0 WS2812_RGB_t WS2812_LED_BUF_CH1[ WS2812_LED_CH1_ANZ ]; #endif #if WS2812_LED_CH2_ANZ>0 WS2812_RGB_t WS2812_LED_BUF_CH2[WS2812_LED_CH2_ANZ]; #endif #if WS2812_LED_CH3_ANZ>0 WS2812_RGB_t WS2812_LED_BUF_CH3[WS2812_LED_CH3_ANZ]; #endif #if WS2812_LED_CH4_ANZ>0 WS2812_RGB_t WS2812_LED_BUF_CH4[WS2812_LED_CH4_ANZ]; #endif //-------------------------------------------------------------- // standard Farben (R,G,B) //-------------------------------------------------------------- #define WS2812_RGB_COL_OFF (WS2812_RGB_t) {0x00,0x00,0x00} #define WS2812_RGB_COL_BLUE (WS2812_RGB_t) {0x00,0x00,0xFF} #define WS2812_RGB_COL_GREEN (WS2812_RGB_t) {0x00,0xFF,0x00} #define WS2812_RGB_COL_RED (WS2812_RGB_t) {0xFF,0x00,0x00} #define WS2812_RGB_COL_WHITE (WS2812_RGB_t) {0xFF,0xFF,0xFF} #define WS2812_RGB_COL_CYAN (WS2812_RGB_t) {0x00,0xFF,0xFF} #define WS2812_RGB_COL_MAGENTA (WS2812_RGB_t) {0xFF,0x00,0xFF} #define WS2812_RGB_COL_YELLOW (WS2812_RGB_t) {0xFF,0xFF,0x00} //-------------------------------------------------------------- // standard Farben (H,S,V) //-------------------------------------------------------------- #define WS2812_HSV_COL_OFF (WS2812_HSV_t) {0, 0, 0} #define WS2812_HSV_COL_BLUE (WS2812_HSV_t) {240,100,100} #define WS2812_HSV_COL_GREEN (WS2812_HSV_t) {120,100,100} #define WS2812_HSV_COL_RED (WS2812_HSV_t) {0, 100,100} #define WS2812_HSV_COL_CYAN (WS2812_HSV_t) {180,100,100} #define WS2812_HSV_COL_MAGENTA (WS2812_HSV_t) {300,100,100} #define WS2812_HSV_COL_YELLOW (WS2812_HSV_t) {60, 100,100} //-------------------------------------------------------------- // WS2812 Timing : (1.25us = 800 kHz) // logische-0 => HI:0.35us , LO:0.90us // logische-1 = HI:0.90us , LO:0.35us // // WS23812 Bit-Format : (8G8R8B) // 24bit pro LED (30us pro LED) // 8bit pro Farbe (MSB first) // Farbreihenfolge : GRB // // nach jedem Frame von n-LEDs kommt eine Pause von >= 50us // // Grundfrequenz (TIM3) = 2*APB1 (APB1=42MHz) => TIM_CLK=84MHz // periode : 0 bis 0xFFFF // prescale : 0 bis 0xFFFF // // PWM-Frq = TIM_CLK/(periode+1)/(vorteiler+1) //-------------------------------------------------------------- #define WS2812_TIM_PRESCALE 0 // F_T3 = 84 MHz (11.9ns) #define WS2812_TIM_PERIODE 104 // F_PWM = 80 kHz (1.25us) #define WS2812_LO_TIME 29 // 29 * 11.9ns = 0.34us #define WS2812_HI_TIME 76 // 76 * 11.9ns = 0.90us //-------------------------------------------------------------- // defines vom WS2812 (nicht abaendern) //-------------------------------------------------------------- #define WS2812_BIT_PER_LED 24 // 3*8bit pro LED #define WS2812_PAUSE_ANZ 2 // fuer Pause (2*30us) #define WS2812_TIMER_BUF_LEN1 (WS2812_LED_CH1_ANZ+WS2812_PAUSE_ANZ)*WS2812_BIT_PER_LED #define WS2812_TIMER_BUF_LEN2 (WS2812_LED_CH2_ANZ+WS2812_PAUSE_ANZ)*WS2812_BIT_PER_LED #define WS2812_TIMER_BUF_LEN3 (WS2812_LED_CH3_ANZ+WS2812_PAUSE_ANZ)*WS2812_BIT_PER_LED #define WS2812_TIMER_BUF_LEN4 (WS2812_LED_CH4_ANZ+WS2812_PAUSE_ANZ)*WS2812_BIT_PER_LED #define WS2812_TIMER_BUF_LEN (WS2812_LED_MAX_ANZ+WS2812_PAUSE_ANZ)*WS2812_BIT_PER_LED //-------------------------------------------------------------- // Globale Funktionen //-------------------------------------------------------------- void UB_WS2812_Init( void ); void UB_WS2812_SetChannel( uint8_t ch ); void UB_WS2812_Refresh( void ); void UB_WS2812_RGB_2_HSV( WS2812_HSV_t hsv_col, WS2812_RGB_t *rgb_col ); void UB_WS2812_One_Led_RGB( uint32_t nr, WS2812_RGB_t rgb_col, uint8_t refresh ); void UB_WS2812_All_Led_RGB( WS2812_RGB_t rgb_col, uint8_t refresh ); void UB_WS2812_One_Led_HSV( uint32_t nr, WS2812_HSV_t hsv_col, uint8_t refresh ); void UB_WS2812_All_Led_HSV( WS2812_HSV_t hsv_col, uint8_t refresh ); void UB_WS2812_Shift_Left( void ); void UB_WS2812_Shift_Right( void ); void UB_WS2812_Rotate_Left( void ); void UB_WS2812_Rotate_Right( void ); //-------------------------------------------------------------- #endif // __STM32F4_UB_WS2812_H
//-------------------------------------------------------------- // File : stm32_ub_ws2812.c // Datum : 25.04.2014 // Version : 1.2 // Autor : UB // EMail : mc-4u(@)t-online.de // Web : www.mikrocontroller-4u.de // CPU : STM32F4 // IDE : CooCox CoIDE 1.7.4 // GCC : 4.7 2012q4 // Module : GPIO, TIM, DMA, MISC // Funktion : RGB-LED mit WS2812-Chip (LED Vcc = 3,3V !!) // (einzelne LED oder bis zu 4 Ketten von n-LEDs) // // Hinweis : es koennen bis zu 4 LED-Ketten betrieben werden // die Anzahl der LEDs pro Kette und der benutzte // GPIO-Pin muss im H-File eingestellt werden // // CH1 = PC6 (LED-Kette mit 5 LEDs) // CH2 = PB5 (nicht aktiv) // CH3 = PB0 (nicht aktiv) // CH4 = PB1 (nicht aktiv) //-------------------------------------------------------------- //-------------------------------------------------------------- // Includes //-------------------------------------------------------------- #include "stm32_ub_ws2812.h" //-------------------------------------------------------------- // Globale interne Variabeln //-------------------------------------------------------------- uint32_t ws2812_dma_status; uint16_t WS2812_TIMER_BUF[ WS2812_TIMER_BUF_LEN ]; uint8_t ws2812_channel; WS2812_RGB_t *ws2812_ptr; uint32_t ws2812_maxanz; //-------------------------------------------------------------- // interne Funktionen //-------------------------------------------------------------- void p_WS2812_clearAll( void ); void p_WS2812_calcTimerBuf( void ); void p_WS2812_InitIO( void ); void p_WS2812_InitTIM( void ); void p_WS2812_InitDMA( void ); void p_WS2812_InitNVIC( void ); void p_WS2812_DMA_Start( void ); //-------------------------------------------------------------- // init aller WS2812-Ketten // alle LEDs ausschalten // (aktiv ist die Kette mit der niedrigsten Channel-Nr) //-------------------------------------------------------------- void UB_WS2812_Init( void ) { uint32_t n; // init aller Variabeln ws2812_dma_status = 0; ws2812_channel = 0; ws2812_maxanz = 0; // init vom Timer Array for ( n = 0; n < WS2812_TIMER_BUF_LEN; n++ ) { WS2812_TIMER_BUF[ n ] = 0; // 0 => fuer Pausenzeit } // init der LED Arrays aller Ketten #if WS2812_LED_CH4_ANZ>0 for(n=0;n<WS2812_LED_CH4_ANZ;n++) { WS2812_LED_BUF_CH4[n]=WS2812_RGB_COL_OFF; } ws2812_channel=4; #endif #if WS2812_LED_CH3_ANZ>0 for(n=0;n<WS2812_LED_CH3_ANZ;n++) { WS2812_LED_BUF_CH3[n]=WS2812_RGB_COL_OFF; } ws2812_channel=3; #endif #if WS2812_LED_CH2_ANZ>0 for(n=0;n<WS2812_LED_CH2_ANZ;n++) { WS2812_LED_BUF_CH2[n]=WS2812_RGB_COL_OFF; } ws2812_channel=2; #endif #if WS2812_LED_CH1_ANZ>0 for(n=0;n<WS2812_LED_CH1_ANZ;n++) { WS2812_LED_BUF_CH1[n]=WS2812_RGB_COL_OFF; } ws2812_channel=1; #endif if ( ws2812_channel == 0 ) return; // aktive WS2812-Kette auswaehlen UB_WS2812_SetChannel( ws2812_channel ); // init vom GPIO p_WS2812_InitIO( ); // init vom Timer p_WS2812_InitTIM( ); // init vom NVIC p_WS2812_InitNVIC( ); // init vom DMA p_WS2812_InitDMA( ); // alle WS2812-Ketten loeschen p_WS2812_clearAll( ); } //-------------------------------------------------------------- // auswahl welche WS2812-Kette aktiv sein soll // (LED Anzahl der Kette muss >0 sein) // ch = [1...4] //-------------------------------------------------------------- void UB_WS2812_SetChannel( uint8_t ch ) { #if WS2812_LED_CH1_ANZ>0 if(ch==1) { ws2812_channel=1; ws2812_ptr=&WS2812_LED_BUF_CH1[0]; ws2812_maxanz=WS2812_LED_CH1_ANZ; } #endif #if WS2812_LED_CH2_ANZ>0 if(ch==2) { ws2812_channel=2; ws2812_ptr=&WS2812_LED_BUF_CH2[0]; ws2812_maxanz=WS2812_LED_CH2_ANZ; } #endif #if WS2812_LED_CH3_ANZ>0 if(ch==3) { ws2812_channel=3; ws2812_ptr=&WS2812_LED_BUF_CH3[0]; ws2812_maxanz=WS2812_LED_CH3_ANZ; } #endif #if WS2812_LED_CH4_ANZ>0 if(ch==4) { ws2812_channel=4; ws2812_ptr=&WS2812_LED_BUF_CH4[0]; ws2812_maxanz=WS2812_LED_CH4_ANZ; } #endif } //-------------------------------------------------------------- // Refresh der aktiven WS2812-Kette // (update aller LEDs) // Die RGB-Farbwerte der LEDs muss im Array "WS2812_LED_BUF[n]" stehen // n = [0...WS2812_LED_ANZ-1] //-------------------------------------------------------------- void UB_WS2812_Refresh( void ) { if ( ws2812_channel == 0 ) return; // warte bis DMA-Transfer fertig while ( ws2812_dma_status != 0 ) ; // Timer Werte berrechnen p_WS2812_calcTimerBuf( ); // DMA starten p_WS2812_DMA_Start( ); } //-------------------------------------------------------------- // wandelt einen HSV-Farbwert in einen RGB-Farbwert um // (Funktion von UlrichRadig.de) //-------------------------------------------------------------- void UB_WS2812_RGB_2_HSV( WS2812_HSV_t hsv_col, WS2812_RGB_t *rgb_col ) { uint8_t diff; // Grenzwerte if ( hsv_col.h > 359 ) hsv_col.h = 359; if ( hsv_col.s > 100 ) hsv_col.s = 100; if ( hsv_col.v > 100 ) hsv_col.v = 100; if ( hsv_col.h < 61 ) { rgb_col->red = 255; rgb_col->green = ( 425 * hsv_col.h ) / 100; rgb_col->blue = 0; } else if ( hsv_col.h < 121 ) { rgb_col->red = 255 - ( ( 425 * ( hsv_col.h - 60 ) ) / 100 ); rgb_col->green = 255; rgb_col->blue = 0; } else if ( hsv_col.h < 181 ) { rgb_col->red = 0; rgb_col->green = 255; rgb_col->blue = ( 425 * ( hsv_col.h - 120 ) ) / 100; } else if ( hsv_col.h < 241 ) { rgb_col->red = 0; rgb_col->green = 255 - ( ( 425 * ( hsv_col.h - 180 ) ) / 100 ); rgb_col->blue = 255; } else if ( hsv_col.h < 301 ) { rgb_col->red = ( 425 * ( hsv_col.h - 240 ) ) / 100; rgb_col->green = 0; rgb_col->blue = 255; } else { rgb_col->red = 255; rgb_col->green = 0; rgb_col->blue = 255 - ( ( 425 * ( hsv_col.h - 300 ) ) / 100 ); } hsv_col.s = 100 - hsv_col.s; diff = ( ( 255 - rgb_col->red ) * hsv_col.s ) / 100; rgb_col->red = rgb_col->red + diff; diff = ( ( 255 - rgb_col->green ) * hsv_col.s ) / 100; rgb_col->green = rgb_col->green + diff; diff = ( ( 255 - rgb_col->blue ) * hsv_col.s ) / 100; rgb_col->blue = rgb_col->blue + diff; rgb_col->red = ( rgb_col->red * hsv_col.v ) / 100; rgb_col->green = ( rgb_col->green * hsv_col.v ) / 100; rgb_col->blue = ( rgb_col->blue * hsv_col.v ) / 100; } //-------------------------------------------------------------- // eine LED der aktiven WS2812-Kette auf eine Farbe setzen (RGB) // nr : [0...WS2812_LED_ANZ-1] // rgb_col : Farbwert (in RGB) // refresh : 0=ohne refresh, 1=mit refresh //-------------------------------------------------------------- void UB_WS2812_One_Led_RGB( uint32_t nr, WS2812_RGB_t rgb_col, uint8_t refresh ) { if ( ws2812_channel == 0 ) return; if ( nr < ws2812_maxanz ) { ws2812_ptr[ nr ] = rgb_col; if ( refresh == 1 ) UB_WS2812_Refresh( ); } } //-------------------------------------------------------------- // alle LEDs der aktiven WS2812-Kette auf eine Farbe setzen (RGB) // rgb_col : Farbwert (in RGB) // refresh : 0=ohne refresh, 1=mit refresh //-------------------------------------------------------------- void UB_WS2812_All_Led_RGB( WS2812_RGB_t rgb_col, uint8_t refresh ) { uint32_t n; if ( ws2812_channel == 0 ) return; for ( n = 0; n < ws2812_maxanz; n++ ) { ws2812_ptr[ n ] = rgb_col; } if ( refresh == 1 ) UB_WS2812_Refresh( ); } //-------------------------------------------------------------- // eine LED der aktiven WS2812-Kette auf eine Farbe setzen (HSV) // nr : [0...WS2812_LED_ANZ-1] // hsv_col : Farbwert (in HSV) // refresh : 0=ohne refresh, 1=mit refresh //-------------------------------------------------------------- void UB_WS2812_One_Led_HSV( uint32_t nr, WS2812_HSV_t hsv_col, uint8_t refresh ) { WS2812_RGB_t rgb_col; if ( ws2812_channel == 0 ) return; if ( nr < ws2812_maxanz ) { // farbe in RGB umwandeln UB_WS2812_RGB_2_HSV( hsv_col, &rgb_col ); ws2812_ptr[ nr ] = rgb_col; if ( refresh == 1 ) UB_WS2812_Refresh( ); } } //-------------------------------------------------------------- // alle LEDs der aktiven WS2812-Kette auf eine Farbe setzen (HSV) // hsv_col : Farbwert (in HSV) // refresh : 0=ohne refresh, 1=mit refresh //-------------------------------------------------------------- void UB_WS2812_All_Led_HSV( WS2812_HSV_t hsv_col, uint8_t refresh ) { uint32_t n; WS2812_RGB_t rgb_col; if ( ws2812_channel == 0 ) return; // farbe in RGB umwandeln UB_WS2812_RGB_2_HSV( hsv_col, &rgb_col ); for ( n = 0; n < ws2812_maxanz; n++ ) { ws2812_ptr[ n ] = rgb_col; } if ( refresh == 1 ) UB_WS2812_Refresh( ); } //-------------------------------------------------------------- // alle LEDs der aktiven WS2812-Kette eine position nach links schieben // letzte LED wird ausgeschaltet //-------------------------------------------------------------- void UB_WS2812_Shift_Left( void ) { uint32_t n; if ( ws2812_channel == 0 ) return; if ( ws2812_maxanz > 1 ) { for ( n = 1; n < ws2812_maxanz; n++ ) { ws2812_ptr[ n - 1 ] = ws2812_ptr[ n ]; } ws2812_ptr[ n - 1 ] = WS2812_RGB_COL_OFF; UB_WS2812_Refresh( ); } } //-------------------------------------------------------------- // alle LEDs der aktiven WS2812-Kette eine position nach rechts schieben // erste LED wird ausgeschaltet //-------------------------------------------------------------- void UB_WS2812_Shift_Right( void ) { uint32_t n; if ( ws2812_channel == 0 ) return; if ( ws2812_maxanz > 1 ) { for ( n = ws2812_maxanz - 1; n > 0; n-- ) { ws2812_ptr[ n ] = ws2812_ptr[ n - 1 ]; } ws2812_ptr[ n ] = WS2812_RGB_COL_OFF; UB_WS2812_Refresh( ); } } //-------------------------------------------------------------- // alle LEDs der aktiven WS2812-Kette eine position nach links rotieren // letzte LED bekommt den Farbwert der ersten LED //-------------------------------------------------------------- void UB_WS2812_Rotate_Left( void ) { uint32_t n; WS2812_RGB_t d; if ( ws2812_channel == 0 ) return; if ( ws2812_maxanz > 1 ) { d = ws2812_ptr[ 0 ]; for ( n = 1; n < ws2812_maxanz; n++ ) { ws2812_ptr[ n - 1 ] = ws2812_ptr[ n ]; } ws2812_ptr[ n - 1 ] = d; UB_WS2812_Refresh( ); } } //-------------------------------------------------------------- // alle LEDs der aktiven WS2812-Kette eine position nach rechts rotieren // erste LED bekommt den Farbwert der letzten LED //-------------------------------------------------------------- void UB_WS2812_Rotate_Right( void ) { uint32_t n; WS2812_RGB_t d; if ( ws2812_channel == 0 ) return; if ( ws2812_maxanz > 1 ) { d = ws2812_ptr[ ws2812_maxanz - 1 ]; for ( n = ws2812_maxanz - 1; n > 0; n-- ) { ws2812_ptr[ n ] = ws2812_ptr[ n - 1 ]; } ws2812_ptr[ n ] = d; UB_WS2812_Refresh( ); } } //-------------------------------------------------------------- // interne Funktion // loescht alle WS2812-Ketten //-------------------------------------------------------------- void p_WS2812_clearAll( void ) { //------------------------- // einmal DMA starten // (ohne Signal, Dauer LoPegel) //------------------------- if ( WS2812_LED_CH4_ANZ > 0 ) { // auf Kanal 4 schalten UB_WS2812_SetChannel( 4 ); // warte bis DMA-Transfer fertig while ( ws2812_dma_status != 0 ) ; // DMA starten p_WS2812_DMA_Start( ); } if ( WS2812_LED_CH3_ANZ > 0 ) { // auf Kanal 3 schalten UB_WS2812_SetChannel( 3 ); // warte bis DMA-Transfer fertig while ( ws2812_dma_status != 0 ) ; // DMA starten p_WS2812_DMA_Start( ); } if ( WS2812_LED_CH2_ANZ > 0 ) { // auf Kanal 2 schalten UB_WS2812_SetChannel( 2 ); // warte bis DMA-Transfer fertig while ( ws2812_dma_status != 0 ) ; // DMA starten p_WS2812_DMA_Start( ); } if ( WS2812_LED_CH1_ANZ > 0 ) { // auf Kanal 1 schalten UB_WS2812_SetChannel( 1 ); // warte bis DMA-Transfer fertig while ( ws2812_dma_status != 0 ) ; // DMA starten p_WS2812_DMA_Start( ); } //------------------------- // alle LEDs ausschalten //------------------------- if ( WS2812_LED_CH4_ANZ > 0 ) { // auf Kanal 4 schalten UB_WS2812_SetChannel( 4 ); UB_WS2812_All_Led_RGB( WS2812_RGB_COL_OFF, 1 ); } if ( WS2812_LED_CH3_ANZ > 0 ) { // auf Kanal 3 schalten UB_WS2812_SetChannel( 3 ); UB_WS2812_All_Led_RGB( WS2812_RGB_COL_OFF, 1 ); } if ( WS2812_LED_CH2_ANZ > 0 ) { // auf Kanal 2 schalten UB_WS2812_SetChannel( 2 ); UB_WS2812_All_Led_RGB( WS2812_RGB_COL_OFF, 1 ); } if ( WS2812_LED_CH1_ANZ > 0 ) { // auf Kanal 1 schalten UB_WS2812_SetChannel( 1 ); UB_WS2812_All_Led_RGB( WS2812_RGB_COL_OFF, 1 ); } } //-------------------------------------------------------------- // interne Funktion // errechnet aus den RGB-Farbwerten der aktiven LEDs // die notwendigen PWM-Werte fuer die Datenleitung //-------------------------------------------------------------- void p_WS2812_calcTimerBuf( void ) { uint32_t n; uint32_t pos; WS2812_RGB_t led; if ( ws2812_channel == 0 ) return; pos = 0; // timingzeiten fuer alle LEDs setzen for ( n = 0; n < ws2812_maxanz; n++ ) { led = ws2812_ptr[ n ]; // Col:Green , Bit:7..0 WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x80 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x40 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x20 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x10 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x08 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x04 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x02 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.green & 0x01 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; // Col:Red , Bit:7..0 WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x80 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x40 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x20 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x10 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x08 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x04 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x02 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.red & 0x01 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; // Col:Blue , Bit:7..0 WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x80 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x40 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x20 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x10 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x08 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x04 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x02 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; WS2812_TIMER_BUF[ pos ] = WS2812_LO_TIME; if ( ( led.blue & 0x01 ) != 0 ) WS2812_TIMER_BUF[ pos ] = WS2812_HI_TIME; pos++; } // nach den Farbinformationen eine Pausenzeit anh鋘gen (2*30ms) for ( n = 0; n < WS2812_PAUSE_ANZ * WS2812_BIT_PER_LED; n++ ) { WS2812_TIMER_BUF[ pos ] = 0; // 0 => fuer Pausenzeit pos++; } } //-------------------------------------------------------------- // interne Funktion // DMA und Timer starten // (gestoppt wird per Transfer-Complete-Interrupt) //-------------------------------------------------------------- void p_WS2812_DMA_Start( void ) { if ( ws2812_channel == 0 ) return; // status auf "busy" setzen ws2812_dma_status = 1; // init vom DMA p_WS2812_InitDMA( ); if ( ws2812_channel == 1 ) { // enable vom Transfer-Complete Interrupt DMA_ITConfig( WS2812_DMA_CH1_STREAM, DMA_IT_TC, ENABLE ); // DMA enable DMA_Cmd( WS2812_DMA_CH1_STREAM, ENABLE ); } else if ( ws2812_channel == 2 ) { // enable vom Transfer-Complete Interrupt DMA_ITConfig( WS2812_DMA_CH2_STREAM, DMA_IT_TC, ENABLE ); // DMA enable DMA_Cmd( WS2812_DMA_CH2_STREAM, ENABLE ); } else if ( ws2812_channel == 3 ) { // enable vom Transfer-Complete Interrupt DMA_ITConfig( WS2812_DMA_CH3_STREAM, DMA_IT_TC, ENABLE ); // DMA enable DMA_Cmd( WS2812_DMA_CH3_STREAM, ENABLE ); } else if ( ws2812_channel == 4 ) { // enable vom Transfer-Complete Interrupt DMA_ITConfig( WS2812_DMA_CH4_STREAM, DMA_IT_TC, ENABLE ); // DMA enable DMA_Cmd( WS2812_DMA_CH4_STREAM, ENABLE ); } // Timer enable TIM_Cmd( WS2812_TIM, ENABLE ); } //-------------------------------------------------------------- // interne Funktion // init vom GPIO Pin //-------------------------------------------------------------- void p_WS2812_InitIO( void ) { GPIO_InitTypeDef GPIO_InitStructure; #if WS2812_LED_CH1_ANZ>0 // Clock Enable RCC_AHB1PeriphClockCmd(WS2812_CH1_CLOCK, ENABLE); // Config des Pins als Digital-Ausgang GPIO_InitStructure.GPIO_Pin = WS2812_CH1_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(WS2812_CH1_PORT, &GPIO_InitStructure); // Lo-Pegel ausgeben WS2812_CH1_PORT->BSRRH = WS2812_CH1_PIN; // Alternative-Funktion mit dem IO-Pin verbinden GPIO_PinAFConfig(WS2812_CH1_PORT, WS2812_CH1_SOURCE, WS2812_TIM_AF); #endif #if WS2812_LED_CH2_ANZ>0 // Clock Enable RCC_AHB1PeriphClockCmd(WS2812_CH2_CLOCK, ENABLE); // Config des Pins als Digital-Ausgang GPIO_InitStructure.GPIO_Pin = WS2812_CH2_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(WS2812_CH2_PORT, &GPIO_InitStructure); // Lo-Pegel ausgeben WS2812_CH2_PORT->BSRRH = WS2812_CH2_PIN; // Alternative-Funktion mit dem IO-Pin verbinden GPIO_PinAFConfig(WS2812_CH2_PORT, WS2812_CH2_SOURCE, WS2812_TIM_AF); #endif #if WS2812_LED_CH3_ANZ>0 // Clock Enable RCC_AHB1PeriphClockCmd(WS2812_CH3_CLOCK, ENABLE); // Config des Pins als Digital-Ausgang GPIO_InitStructure.GPIO_Pin = WS2812_CH3_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(WS2812_CH3_PORT, &GPIO_InitStructure); // Lo-Pegel ausgeben WS2812_CH3_PORT->BSRRH = WS2812_CH3_PIN; // Alternative-Funktion mit dem IO-Pin verbinden GPIO_PinAFConfig(WS2812_CH3_PORT, WS2812_CH3_SOURCE, WS2812_TIM_AF); #endif #if WS2812_LED_CH4_ANZ>0 // Clock Enable RCC_AHB1PeriphClockCmd(WS2812_CH4_CLOCK, ENABLE); // Config des Pins als Digital-Ausgang GPIO_InitStructure.GPIO_Pin = WS2812_CH4_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(WS2812_CH4_PORT, &GPIO_InitStructure); // Lo-Pegel ausgeben WS2812_CH4_PORT->BSRRH = WS2812_CH4_PIN; // Alternative-Funktion mit dem IO-Pin verbinden GPIO_PinAFConfig(WS2812_CH4_PORT, WS2812_CH4_SOURCE, WS2812_TIM_AF); #endif } //-------------------------------------------------------------- // interne Funktion // init vom Timer //-------------------------------------------------------------- void p_WS2812_InitTIM( void ) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // Clock enable (TIM) RCC_APB1PeriphClockCmd( WS2812_TIM_CLOCK, ENABLE ); // Clock Enable (DMA) RCC_AHB1PeriphClockCmd( WS2812_DMA_CLOCK, ENABLE ); // Timer init TIM_TimeBaseStructure.TIM_Period = WS2812_TIM_PERIODE; TIM_TimeBaseStructure.TIM_Prescaler = WS2812_TIM_PRESCALE; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit( WS2812_TIM, &TIM_TimeBaseStructure ); 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; #if WS2812_LED_CH1_ANZ>0 TIM_OC1Init(WS2812_TIM, &TIM_OCInitStructure); TIM_OC1PreloadConfig(WS2812_TIM, TIM_OCPreload_Enable); #endif #if WS2812_LED_CH2_ANZ>0 TIM_OC2Init(WS2812_TIM, &TIM_OCInitStructure); TIM_OC2PreloadConfig(WS2812_TIM, TIM_OCPreload_Enable); #endif #if WS2812_LED_CH3_ANZ>0 TIM_OC3Init(WS2812_TIM, &TIM_OCInitStructure); TIM_OC3PreloadConfig(WS2812_TIM, TIM_OCPreload_Enable); #endif #if WS2812_LED_CH4_ANZ>0 TIM_OC4Init(WS2812_TIM, &TIM_OCInitStructure); TIM_OC4PreloadConfig(WS2812_TIM, TIM_OCPreload_Enable); #endif // Timer enable TIM_ARRPreloadConfig( WS2812_TIM, ENABLE ); } //-------------------------------------------------------------- // interne Funktion // init vom DMA //-------------------------------------------------------------- void p_WS2812_InitDMA( void ) { DMA_InitTypeDef DMA_InitStructure; if ( ws2812_channel == 0 ) return; // DMA init if ( ws2812_channel == 1 ) { DMA_Cmd( WS2812_DMA_CH1_STREAM, DISABLE ); DMA_DeInit( WS2812_DMA_CH1_STREAM ); DMA_InitStructure.DMA_Channel = WS2812_DMA_CH1_CHANNEL; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &WS2812_TIM_CCR_REG1; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) WS2812_TIMER_BUF; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = WS2812_TIMER_BUF_LEN1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16bit DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init( WS2812_DMA_CH1_STREAM, &DMA_InitStructure ); } else if ( ws2812_channel == 2 ) { DMA_Cmd( WS2812_DMA_CH2_STREAM, DISABLE ); DMA_DeInit( WS2812_DMA_CH2_STREAM ); DMA_InitStructure.DMA_Channel = WS2812_DMA_CH2_CHANNEL; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &WS2812_TIM_CCR_REG2; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) WS2812_TIMER_BUF; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = WS2812_TIMER_BUF_LEN2; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16bit DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init( WS2812_DMA_CH2_STREAM, &DMA_InitStructure ); } else if ( ws2812_channel == 3 ) { DMA_Cmd( WS2812_DMA_CH3_STREAM, DISABLE ); DMA_DeInit( WS2812_DMA_CH3_STREAM ); DMA_InitStructure.DMA_Channel = WS2812_DMA_CH3_CHANNEL; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &WS2812_TIM_CCR_REG3; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) WS2812_TIMER_BUF; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = WS2812_TIMER_BUF_LEN3; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16bit DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init( WS2812_DMA_CH3_STREAM, &DMA_InitStructure ); } else if ( ws2812_channel == 4 ) { DMA_Cmd( WS2812_DMA_CH4_STREAM, DISABLE ); DMA_DeInit( WS2812_DMA_CH4_STREAM ); DMA_InitStructure.DMA_Channel = WS2812_DMA_CH4_CHANNEL; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &WS2812_TIM_CCR_REG4; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) WS2812_TIMER_BUF; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = WS2812_TIMER_BUF_LEN4; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16bit DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init( WS2812_DMA_CH4_STREAM, &DMA_InitStructure ); } } //-------------------------------------------------------------- // interne Funktion // init vom NVIC //-------------------------------------------------------------- void p_WS2812_InitNVIC( void ) { NVIC_InitTypeDef NVIC_InitStructure; #if WS2812_LED_CH1_ANZ>0 TIM_DMACmd(WS2812_TIM, WS2812_TIM_DMA_TRG1, ENABLE); #endif #if WS2812_LED_CH2_ANZ>0 TIM_DMACmd(WS2812_TIM, WS2812_TIM_DMA_TRG2, ENABLE); #endif #if WS2812_LED_CH3_ANZ>0 TIM_DMACmd(WS2812_TIM, WS2812_TIM_DMA_TRG3, ENABLE); #endif #if WS2812_LED_CH4_ANZ>0 TIM_DMACmd(WS2812_TIM, WS2812_TIM_DMA_TRG4, ENABLE); #endif #if WS2812_LED_CH1_ANZ>0 NVIC_InitStructure.NVIC_IRQChannel = WS2812_DMA_CH1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); #endif #if WS2812_LED_CH2_ANZ>0 NVIC_InitStructure.NVIC_IRQChannel = WS2812_DMA_CH2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); #endif #if WS2812_LED_CH3_ANZ>0 NVIC_InitStructure.NVIC_IRQChannel = WS2812_DMA_CH3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); #endif #if WS2812_LED_CH4_ANZ>0 NVIC_InitStructure.NVIC_IRQChannel = WS2812_DMA_CH4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); #endif } //-------------------------------------------------------------- // interne Funktion // ISR vom DMA (CH1) // (wird aufgerufen, wenn alle Daten uebertragen wurden) //-------------------------------------------------------------- void WS2812_DMA_CH1_ISR( void ) { // Test auf Transfer-Complete Interrupt Flag if ( DMA_GetITStatus( WS2812_DMA_CH1_STREAM, WS2812_DMA_CH1_IRQ_FLAG ) ) { // Flag zuruecksetzen DMA_ClearITPendingBit( WS2812_DMA_CH1_STREAM, WS2812_DMA_CH1_IRQ_FLAG ); // Timer disable TIM_Cmd( WS2812_TIM, DISABLE ); // DMA disable DMA_Cmd( WS2812_DMA_CH1_STREAM, DISABLE ); // status auf "ready" setzen ws2812_dma_status = 0; } } //-------------------------------------------------------------- // interne Funktion // ISR vom DMA (CH2) // (wird aufgerufen, wenn alle Daten uebertragen wurden) //-------------------------------------------------------------- void WS2812_DMA_CH2_ISR( void ) { // Test auf Transfer-Complete Interrupt Flag if ( DMA_GetITStatus( WS2812_DMA_CH2_STREAM, WS2812_DMA_CH2_IRQ_FLAG ) ) { // Flag zuruecksetzen DMA_ClearITPendingBit( WS2812_DMA_CH2_STREAM, WS2812_DMA_CH2_IRQ_FLAG ); // Timer disable TIM_Cmd( WS2812_TIM, DISABLE ); // DMA disable DMA_Cmd( WS2812_DMA_CH2_STREAM, DISABLE ); // status auf "ready" setzen ws2812_dma_status = 0; } } //-------------------------------------------------------------- // interne Funktion // ISR vom DMA (CH3) // (wird aufgerufen, wenn alle Daten uebertragen wurden) //-------------------------------------------------------------- void WS2812_DMA_CH3_ISR( void ) { // Test auf Transfer-Complete Interrupt Flag if ( DMA_GetITStatus( WS2812_DMA_CH3_STREAM, WS2812_DMA_CH3_IRQ_FLAG ) ) { // Flag zuruecksetzen DMA_ClearITPendingBit( WS2812_DMA_CH3_STREAM, WS2812_DMA_CH3_IRQ_FLAG ); // Timer disable TIM_Cmd( WS2812_TIM, DISABLE ); // DMA disable DMA_Cmd( WS2812_DMA_CH3_STREAM, DISABLE ); // status auf "ready" setzen ws2812_dma_status = 0; } } //-------------------------------------------------------------- // interne Funktion // ISR vom DMA (CH4) // (wird aufgerufen, wenn alle Daten uebertragen wurden) //-------------------------------------------------------------- void WS2812_DMA_CH4_ISR( void ) { // Test auf Transfer-Complete Interrupt Flag if ( DMA_GetITStatus( WS2812_DMA_CH4_STREAM, WS2812_DMA_CH4_IRQ_FLAG ) ) { // Flag zuruecksetzen DMA_ClearITPendingBit( WS2812_DMA_CH4_STREAM, WS2812_DMA_CH4_IRQ_FLAG ); // Timer disable TIM_Cmd( WS2812_TIM, DISABLE ); // DMA disable DMA_Cmd( WS2812_DMA_CH4_STREAM, DISABLE ); // status auf "ready" setzen ws2812_dma_status = 0; } }