#include #include #include #include #include #define RING_MAX_LED 32u #define MAX_TEMP_CELSIUS 70 enum ring_modes { RING_MODE_WHITE_DISCRETE, /*!< only discrete white LEDs */ RING_MODE_RED, /*!< only red SK6812 */ RING_MODE_GREEN, /*!< only green SK6812 */ RING_MODE_BLUE, /*!< only blue SK6812 */ RING_MODE_ALL, /*!< control all LEDs at once */ RING_MODE_ARC, /*!< SK6812 closing ring */ RING_MODE_QUARTER, /*!< SK6812 walking quarter */ RING_MODE_IN_FARBE_UND_BUNT, /*!< SK6812 color mix */ RING_MODE_MAX, /*!< end of list */ RING_MODE_WAIT_DMX, RING_MODE_WAIT_DMX_BREAK }; volatile int32_t temperature; extern void sk6812_send_led(uint32_t rgbw); volatile uint32_t wait_tick = 0; volatile bool blink_tick = false; static void wait_for_ticks(uint32_t ticks) { wait_tick = 0; while (wait_tick < ticks); } int main(void) { uint32_t led_val = 0x00UL; uint32_t last_led_val = 0x00UL; uint32_t led_calc_val[RING_MAX_LED] = {0x00UL}; uint8_t led_pwm_val = 0u; const uint8_t *dmx_data; bool button_pressed = false; bool force_led_update; bool overtemp_flag = false; enum ring_modes mode; /* Led value / mode before going to DMX */ uint32_t led_val_before_dmx = 0u; enum ring_modes mode_before_dmx = RING_MODE_RED; /* Init to save value */ RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN; GPIOA->MODER |= (2<<7*2)|(2<<6*2)|(1<<3*2); /* enable pullups on encoder inputs */ GPIOA->PUPDR |= (1<<7*2)|(1<<6*2)|(1<<0*2); /* enable TIM3 on encoder inputs */ GPIOA->AFR[0] |= (1<<7*4)|(1<<6*4); /* enable PWM output for magic LED regulator */ GPIOB->MODER |= (2<<1*2); GPIOB->AFR[0] &= ~(0<<1*4); /*! -# init the TIM3 to read the encoder */ TIM3->ARR = 0xFFFF; TIM3->CNT = 0; TIM3->CR2 = 0; TIM3->SMCR = TIM_SMCR_SMS_0; TIM3->CCMR1 = TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_1; TIM3->CCER = TIM_CCER_CC1P | TIM_CCER_CC2P; TIM3->PSC = 0; TIM3->CR1 = TIM_CR1_CEN; /*! -# Init TIM14 for PWM control of the magic LED driver */ /*! -# Count up to 255 (8 bit resolution) */ TIM14->ARR = 0x00FFu; TIM14->CNT = 0u; TIM14->CCR1 = 0u; /*! -# Set prescaler to 11 ==> ca. 17 KHz */ TIM14->PSC = 11u - 1u; /*! -# PWM Mode 1 + prefetch */ TIM14->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE; /*! -# Enable Output compare 1 */ TIM14->CCER = TIM_CCER_CC1E; /*! -# Finally, enable TIM14 */ TIM14->CR2 = 0; TIM14->CR1 = TIM_CR1_CEN; /*! -# Set initial state to all 25% */ led_val = 64u; mode = RING_MODE_WHITE_DISCRETE; temperature_adc_init(); dmx_init(0u); SysTick_Config(800000); while(1) { force_led_update = false; temperature = temperature_adc_get_temp(); if (led_val != last_led_val || button_pressed) { force_led_update = true; } /*! -# Gradually dim down the LED brightness in case the temperature is too high */ if (overtemp_flag) { if (temperature < (MAX_TEMP_CELSIUS-15) * 10) { overtemp_flag = false; } } else { overtemp_flag = temperature > ((MAX_TEMP_CELSIUS) * 10) ? true : false; } if (overtemp_flag) { if (led_val > 2 && mode < RING_MODE_MAX) led_val--; } if (dmx_poll_break_received()) { /* DMX received. Go to DMX mode. * Save old state */ if (mode < RING_MODE_MAX) { led_val_before_dmx = led_val; mode_before_dmx = mode; } mode = RING_MODE_WAIT_DMX; } led_pwm_val = 0u; switch (mode) { case RING_MODE_ALL: for(int i = 0; i < RING_MAX_LED; i ++) { led_calc_val[i] = (led_val << 24) + (led_val << 16) + (led_val << 8) + led_val; } led_pwm_val = led_val; break; case RING_MODE_RED: for(int i = 0; i < RING_MAX_LED; i ++) { led_calc_val[i] = led_val << 16; } break; case RING_MODE_GREEN: for(int i = 0; i < RING_MAX_LED; i ++) { led_calc_val[i] = led_val << 24; } break; case RING_MODE_BLUE: for(int i = 0; i < RING_MAX_LED; i ++) { led_calc_val[i] = led_val << 8; } break; case RING_MODE_WHITE_DISCRETE: for(int i = 0; i < RING_MAX_LED; i ++) { led_calc_val[i] = 0u; } led_pwm_val = led_val; break; case RING_MODE_ARC: for(int i = 0; i < RING_MAX_LED; i ++) { if(led_val > i*8) { led_calc_val[i] = 0xFFFFFFFFUL; } else { led_calc_val[i] = 0x00000000UL; } } break; case RING_MODE_QUARTER: for(int i = 0; i < RING_MAX_LED; i ++) { if((led_val / 7 > i) && (led_val / 7 < (i + 7))) { led_calc_val[i] = 0xFFFFFFFFUL; } else { led_calc_val[i] = 0x00000000UL; } } break; case RING_MODE_IN_FARBE_UND_BUNT: for(int i = 0; i < RING_MAX_LED; i ++) { switch ((led_val + (i / 3)) % 3) { case 0: led_calc_val[i] = 0x00FF0000UL; break; case 1: led_calc_val[i] = 0xFF000000UL; break; case 2: led_calc_val[i] = 0x0000FF00UL; break; default: break; } } break; case RING_MODE_WAIT_DMX: force_led_update = false; if (dmx_enough_data_received() && !overtemp_flag) { dmx_data = dmx_get_data(); mode = RING_MODE_WAIT_DMX_BREAK; if (dmx_data[0] != 0) break; for (int i = 0; i < RING_MAX_LED; i++) { led_calc_val[i] = (dmx_data[1 + i*4 + 3]) | (dmx_data[1 + i*4 + 2] << 8) | (dmx_data[1 + i*4 + 0] << 16) | (dmx_data[1 + i*4 + 1] << 24); } led_pwm_val = dmx_data[129]; force_led_update = true; } else if (overtemp_flag) { force_led_update = true; for (int i = 0; i < RING_MAX_LED; i++) { led_calc_val[i] = 0ul; } led_pwm_val = 0; } break; case RING_MODE_WAIT_DMX_BREAK: force_led_update = false; break; default: for(int i = 0; i < RING_MAX_LED; i ++) { led_calc_val[i] = 0x00000000UL; } break; } if (overtemp_flag) { force_led_update = true; led_calc_val[0] = blink_tick ? 0x00FF0000UL : 0UL; } if (force_led_update) { TIM14->CCR1 = led_pwm_val; for(int i = 0; i < RING_MAX_LED; i ++) { /* Allow interrupts in between LEDs. * They must not exceed the reset length of 80us of SK6812. */ __disable_irq(); sk6812_send_led(led_calc_val[i]); __enable_irq(); } last_led_val = led_val; } /* Only wait in case of non-DMX mode */ if (!(mode == RING_MODE_WAIT_DMX_BREAK || mode == RING_MODE_WAIT_DMX) || overtemp_flag) wait_for_ticks(5); if((int16_t)TIM3->CNT > (int16_t)led_val) { led_val = 0u; } else if(((int16_t)led_val - (int16_t)TIM3->CNT) > UINT8_MAX) { led_val = 255u; } else { led_val = (int16_t)led_val - (int16_t)TIM3->CNT; } TIM3->CNT = 0u; if(button_pressed) { if(GPIOA->IDR & GPIO_IDR_0) { button_pressed = false; } } else if(!(GPIOA->IDR & GPIO_IDR_0)) { button_pressed = true; /* Button pressed */ if (mode > RING_MODE_MAX) { /* In DMX mode. Abort DMX mode */ mode = mode_before_dmx; led_val = led_val_before_dmx; } else { /* Normal mode switching */ mode = (mode + 1) % RING_MODE_MAX; } } } } void SysTick_Handler(void) { static uint32_t tick = 10; if (!--tick) { tick = 10; blink_tick = !blink_tick; } wait_tick++; }