diff --git a/firmware/dmx.c b/firmware/dmx.c index 6202a36..63c1868 100644 --- a/firmware/dmx.c +++ b/firmware/dmx.c @@ -1 +1,65 @@ #include +#include + +static volatile bool dmx_new_data_avail = false; +static uint32_t dmx_base_channel; +static uint8_t dmx_channel_data[DMX_USED_CHANNEL_COUNT]; + +void dmx_init(uint32_t base_channel) +{ + int i; + uint8_t *ptr; + + dmx_new_data_avail = false; + for (i = 0, ptr = dmx_channel_data; i < DMX_USED_CHANNEL_COUNT; i++, ptr++) { + *ptr = 0u; + } + + dmx_base_channel = base_channel; + + /* Enable GPIOA and USART1 clock */ + RCC->AHBENR |= RCC_AHBENR_GPIOAEN; + RCC->APB2ENR |= RCC_APB2ENR_USART1EN; + + /* Switch RXTX pin low, activating permanent READ mode */ + GPIOA->MODER |= (0x1<<(2*5)); + GPIOA->BRR |= (1<<5); + + /* Switch PA10 to RX alternate function of USART1 (AF1) */ + GPIOA->MODER |= (0x2<<(2*10)); + GPIOA->AFR[1] |=(0x1<<(4*2)); + + /* Set baudrate: 48MHz / 250k = 129 */ + USART1->BRR = 192u; + USART1->CR3 = USART_CR3_EIE; + USART1->CR2 = USART_CR2_STOP_1; + USART1->CR1 = USART_CR1_RXNEIE | USART_CR1_RE | USART_CR1_UE; + + NVIC_EnableIRQ(USART1_IRQn); +} + +bool dmx_new_data_available() +{ + return dmx_new_data_avail; +} + +const uint8_t *dmx_get_data() +{ + return dmx_channel_data; +} + +void USART1_IRQHandler(void) +{ + uint32_t isr; + volatile uint8_t dreg; + + isr = USART1->ISR; + USART1->ICR = USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF; + + if (isr & USART_ISR_RXNE) { + dreg = (uint8_t)USART1->RDR; + dmx_channel_data[0] = dreg; + } + + __DSB(); +} diff --git a/firmware/include/ring-light/dmx.h b/firmware/include/ring-light/dmx.h index a50d261..2c35889 100644 --- a/firmware/include/ring-light/dmx.h +++ b/firmware/include/ring-light/dmx.h @@ -1,4 +1,43 @@ #ifndef _DMX_H_ #define _DMX_H_ + + +#include +#include + +#define DMX_UNIVERSE_SIZE (255u) +#define DMX_USED_CHANNEL_COUNT (129u) + +/** + * @brief Init DMX reception + * + * DMX data is received from the base channel onwards: + * - R LED1 + * - G LED1 + * - B LED1 + * - W LED1 + * - R LED2 + * ... + * - W LED32 + * - W DISCRETE + * + * In Sum: 129 8 bit channels + * + * @param base_channel Base channel the ring light will listen on + */ +void dmx_init(uint32_t base_channel); + +/** + * @brief Has new DMX data been received? + * @return true if new data is available + */ +bool dmx_new_data_available(void); + +/** + * @brief Returns the array of the 129 DMX channels + * @return + */ +const uint8_t *dmx_get_data(void); + #endif /* _DMX_H_ */ diff --git a/firmware/main.c b/firmware/main.c index a42b06c..1bba292 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #define RING_MAX_LED 32u #define MAX_TEMP_CELSIUS 70 @@ -37,7 +38,7 @@ int main(void) uint8_t led_pwm_val = 0u; bool button_pressed = false; - enum ring_modes mode = RING_MODE_ALL; + enum ring_modes mode; RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; RCC->APB1ENR |= RCC_APB1ENR_TIM3EN | RCC_APB1ENR_TIM14EN; @@ -83,6 +84,7 @@ int main(void) mode = RING_MODE_WHITE_DISCRETE; temperature_adc_init(); + dmx_init(0u); SysTick_Config(800000); while(1) { @@ -171,11 +173,16 @@ int main(void) } TIM14->CCR1 = led_pwm_val; - __disable_irq(); + 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(); } - __enable_irq(); + wait_for_ticks(5); if((int16_t)TIM3->CNT > (int16_t)led_val) {