Implement first draft of working DMX. Still needs rework and beatifying
This commit is contained in:
parent
d06b2b7eaf
commit
60f1923abe
@ -8,15 +8,14 @@ enum dmx_rx_state_enum {
|
|||||||
DMX_RX_DATA,
|
DMX_RX_DATA,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static volatile bool break_received;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief DMX data received. Contains the whole DMX universe including the first 0 byte.
|
* @brief DMX data received. Contains the whole DMX universe including the first 0 byte.
|
||||||
* The controller does check the first byte to be zero.
|
* The controller does check the first byte to be zero.
|
||||||
*/
|
*/
|
||||||
static volatile uint8_t dmx_channel_data[DMX_UNIVERSE_SIZE + 1];
|
static volatile uint8_t dmx_channel_data[DMX_UNIVERSE_SIZE + 1];
|
||||||
|
|
||||||
static volatile enum dmx_rx_state_enum dmx_rx_state;
|
|
||||||
static volatile uint32_t dmx_write_pointer;
|
|
||||||
|
|
||||||
void dmx_init(uint32_t base_channel)
|
void dmx_init(uint32_t base_channel)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -27,11 +26,10 @@ void dmx_init(uint32_t base_channel)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dmx_base_channel = base_channel;
|
dmx_base_channel = base_channel;
|
||||||
dmx_write_pointer = 0u;
|
break_received = false;
|
||||||
dmx_rx_state = DMX_RX_WAIT_FOR_BREAK;
|
|
||||||
|
|
||||||
/* Enable GPIOA and USART1 clock */
|
/* Enable GPIOA and USART1 clock */
|
||||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
|
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN;
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||||
|
|
||||||
/* Switch RXTX pin low, activating permanent READ mode */
|
/* Switch RXTX pin low, activating permanent READ mode */
|
||||||
@ -51,49 +49,78 @@ void dmx_init(uint32_t base_channel)
|
|||||||
/* Map USART1 RX to DMA Channel 3 */
|
/* Map USART1 RX to DMA Channel 3 */
|
||||||
SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_USART1RX_DMA_RMP;
|
SYSCFG->CFGR1 &= ~SYSCFG_CFGR1_USART1RX_DMA_RMP;
|
||||||
|
|
||||||
|
DMA1_Channel3->CCR = DMA_CCR_PL_1 | DMA_CCR_MINC | DMA_CCR_TCIE;
|
||||||
|
|
||||||
|
NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
|
||||||
NVIC_EnableIRQ(USART1_IRQn);
|
NVIC_EnableIRQ(USART1_IRQn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const uint8_t *dmx_get_data()
|
const uint8_t *dmx_get_data()
|
||||||
{
|
{
|
||||||
return (const uint8_t *)&dmx_channel_data[1];
|
return (const uint8_t *)dmx_channel_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void USART1_IRQHandler(void)
|
void USART1_IRQHandler(void)
|
||||||
{
|
{
|
||||||
uint32_t isr;
|
uint32_t isr;
|
||||||
uint8_t dreg;
|
|
||||||
|
|
||||||
isr = USART1->ISR;
|
isr = USART1->ISR;
|
||||||
USART1->ICR = USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF;
|
USART1->ICR = USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF;
|
||||||
|
|
||||||
if (isr & USART_ISR_FE) {
|
if (isr & USART_ISR_FE) {
|
||||||
/* Frame error received. Start of DMX frame */
|
/* Frame error received. Start of DMX frame */
|
||||||
dmx_write_pointer = 0u;
|
|
||||||
dmx_rx_state = DMX_RX_DATA;
|
|
||||||
/* Flush RX data */
|
/* Flush RX data */
|
||||||
USART1->RQR = USART_RQR_RXFRQ;
|
USART1->RQR = USART_RQR_RXFRQ;
|
||||||
|
USART1->CR3 |= USART_CR3_DMAR;
|
||||||
|
DMA1_Channel3->CCR &= ~DMA_CCR_EN;
|
||||||
|
DMA1_Channel3->CMAR = (uint32_t)dmx_channel_data;
|
||||||
|
DMA1_Channel3->CPAR = (uint32_t)&USART1->RDR;
|
||||||
|
DMA1_Channel3->CNDTR = DMX_UNIVERSE_SIZE + 1;
|
||||||
|
DMA1_Channel3->CCR |= DMA_CCR_EN;
|
||||||
|
USART1->CR3 |= USART_CR3_DMAR;
|
||||||
|
break_received = true;
|
||||||
} else if (isr & USART_ISR_RXNE) {
|
} else if (isr & USART_ISR_RXNE) {
|
||||||
/* Received valid symbol */
|
|
||||||
dreg = (uint8_t)USART1->RDR;
|
|
||||||
|
|
||||||
if (dmx_rx_state == DMX_RX_DATA) {
|
|
||||||
/* Ready to recieve data */
|
|
||||||
if (dmx_write_pointer < (DMX_UNIVERSE_SIZE + 1)) {
|
|
||||||
dmx_channel_data[dmx_write_pointer] = dreg;
|
|
||||||
dmx_write_pointer++;
|
|
||||||
} else {
|
|
||||||
dmx_rx_state = DMX_RX_WAIT_FOR_BREAK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__DSB();
|
__DSB();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DMA_CH2_3_DMA2_CH1_2_IRQHandler()
|
void DMA_CH2_3_DMA2_CH1_2_IRQHandler(void)
|
||||||
{
|
{
|
||||||
|
uint32_t isr;
|
||||||
|
|
||||||
|
isr = DMA1->ISR;
|
||||||
|
/* Only clear the interupts of channel 2 (bits 11:9) */
|
||||||
|
DMA1->IFCR = isr & 0xF00;
|
||||||
|
|
||||||
|
if (isr & DMA_ISR_TCIF3) {
|
||||||
|
DMA1->ISR;
|
||||||
|
}
|
||||||
|
__DSB();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dmx_poll_break_received(void)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
/* Atomically reset the flag */
|
||||||
|
__disable_irq();
|
||||||
|
ret = break_received;
|
||||||
|
break_received = false;
|
||||||
|
__enable_irq();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dmx_enough_data_received()
|
||||||
|
{
|
||||||
|
uint32_t received_count = (DMX_UNIVERSE_SIZE + 1) - DMA1_Channel3->CNDTR;
|
||||||
|
|
||||||
|
if (received_count > (dmx_base_channel + DMX_USED_CHANNEL_COUNT)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,16 @@ void dmx_init(uint32_t base_channel);
|
|||||||
*/
|
*/
|
||||||
const uint8_t *dmx_get_data(void);
|
const uint8_t *dmx_get_data(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a break was received. This resets the flag
|
||||||
|
* @return true if a break was received since the last time calling this function
|
||||||
|
*/
|
||||||
|
bool dmx_poll_break_received(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The DMX receiver has received all data for the ring light. It can be read
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
bool dmx_enough_data_received(void);
|
||||||
|
|
||||||
#endif /* _DMX_H_ */
|
#endif /* _DMX_H_ */
|
||||||
|
@ -16,7 +16,9 @@ enum ring_modes {
|
|||||||
RING_MODE_ARC, /*!< SK6812 closing ring */
|
RING_MODE_ARC, /*!< SK6812 closing ring */
|
||||||
RING_MODE_QUARTER, /*!< SK6812 walking quarter */
|
RING_MODE_QUARTER, /*!< SK6812 walking quarter */
|
||||||
RING_MODE_IN_FARBE_UND_BUNT, /*!< SK6812 color mix */
|
RING_MODE_IN_FARBE_UND_BUNT, /*!< SK6812 color mix */
|
||||||
RING_MODE_MAX /*!< end of list */
|
RING_MODE_MAX, /*!< end of list */
|
||||||
|
RING_MODE_WAIT_DMX,
|
||||||
|
RING_MODE_WAIT_DMX_BREAK
|
||||||
};
|
};
|
||||||
|
|
||||||
volatile int32_t temperature;
|
volatile int32_t temperature;
|
||||||
@ -34,10 +36,13 @@ static void wait_for_ticks(uint32_t ticks)
|
|||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
uint32_t led_val = 0x00UL;
|
uint32_t led_val = 0x00UL;
|
||||||
|
uint32_t last_led_val = 0x00UL;
|
||||||
uint32_t led_calc_val[RING_MAX_LED] = {0x00UL};
|
uint32_t led_calc_val[RING_MAX_LED] = {0x00UL};
|
||||||
uint8_t led_pwm_val = 0u;
|
uint8_t led_pwm_val = 0u;
|
||||||
|
const uint8_t *dmx_data;
|
||||||
|
|
||||||
bool button_pressed = false;
|
bool button_pressed = false;
|
||||||
|
bool force_led_update;
|
||||||
enum ring_modes mode;
|
enum ring_modes mode;
|
||||||
|
|
||||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
|
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN;
|
||||||
@ -88,14 +93,23 @@ int main(void)
|
|||||||
|
|
||||||
SysTick_Config(800000);
|
SysTick_Config(800000);
|
||||||
while(1) {
|
while(1) {
|
||||||
|
force_led_update = false;
|
||||||
temperature = temperature_adc_get_temp();
|
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 */
|
/*! -# Gradually dim down the LED brightness in case the temperature is too high */
|
||||||
if (temperature > ((MAX_TEMP_CELSIUS) * 10)) {
|
if (temperature > ((MAX_TEMP_CELSIUS) * 10)) {
|
||||||
if (led_val > 20)
|
if (led_val > 20)
|
||||||
led_val--;
|
led_val--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dmx_poll_break_received()) {
|
||||||
|
mode = RING_MODE_WAIT_DMX;
|
||||||
|
}
|
||||||
|
|
||||||
led_pwm_val = 0u;
|
led_pwm_val = 0u;
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
@ -165,6 +179,26 @@ int main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case RING_MODE_WAIT_DMX:
|
||||||
|
force_led_update = false;
|
||||||
|
if (dmx_enough_data_received()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RING_MODE_WAIT_DMX_BREAK:
|
||||||
|
force_led_update = false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
for(int i = 0; i < RING_MAX_LED; i ++) {
|
for(int i = 0; i < RING_MAX_LED; i ++) {
|
||||||
led_calc_val[i] = 0x00000000UL;
|
led_calc_val[i] = 0x00000000UL;
|
||||||
@ -172,30 +206,35 @@ int main(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIM14->CCR1 = led_pwm_val;
|
if (force_led_update) {
|
||||||
|
TIM14->CCR1 = led_pwm_val;
|
||||||
|
|
||||||
for(int i = 0; i < RING_MAX_LED; i ++) {
|
for(int i = 0; i < RING_MAX_LED; i ++) {
|
||||||
/* Allow interrupts in between LEDs.
|
/* Allow interrupts in between LEDs.
|
||||||
* They must not exceed the reset length of 80us of SK6812.
|
* They must not exceed the reset length of 80us of SK6812.
|
||||||
*/
|
*/
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
sk6812_send_led(led_calc_val[i]);
|
sk6812_send_led(led_calc_val[i]);
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
}
|
||||||
|
last_led_val = led_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
wait_for_ticks(5);
|
wait_for_ticks(5);
|
||||||
|
|
||||||
if((int16_t)TIM3->CNT > (int16_t)led_val) {
|
if((int16_t)TIM3->CNT > (int16_t)led_val) {
|
||||||
led_val = 0u;
|
led_val = 0u;
|
||||||
}
|
} else if(((int16_t)led_val - (int16_t)TIM3->CNT) > UINT8_MAX) {
|
||||||
else if(((int16_t)led_val - (int16_t)TIM3->CNT) > UINT8_MAX) {
|
|
||||||
led_val = 255u;
|
led_val = 255u;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
led_val = (int16_t)led_val - (int16_t)TIM3->CNT;
|
led_val = (int16_t)led_val - (int16_t)TIM3->CNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIM3->CNT = 0u;
|
TIM3->CNT = 0u;
|
||||||
|
|
||||||
|
|
||||||
if(button_pressed) {
|
if(button_pressed) {
|
||||||
if(GPIOA->IDR & GPIO_IDR_0) {
|
if(GPIOA->IDR & GPIO_IDR_0) {
|
||||||
button_pressed = false;
|
button_pressed = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user