#include "stm32f030x6.h" #include #include #include #include #include static GPIO_TypeDef *dmx_tx_port; static uint8_t dmx_tx_pin; static uint32_t dmx_universe_length; static uint8_t *dmx_data_ptr; static uint16_t dmx_tx_break_len; static uint16_t dmx_tx_break_pause; enum dmx_tx_state { DMX_TX_OFF, DMX_TX_IDLE, DMX_TX_BREAK, DMX_TX_BREAK_PAUSE, DMX_TX_NULLBYTE, DMX_TX_DATA, }; static volatile enum dmx_tx_state tx_state; /* USART1 TX is mapped on DMA Channel2 */ static void dmx_break(bool break_enable) { uint32_t tmp; /* Force pin to low */ dmx_tx_port->BSRR |= (1 << (dmx_tx_pin + 16)); /* Change pin mode from alternate function (UART) to output and vice versa */ tmp = dmx_tx_port->MODER; if (break_enable) { tmp &= MODER_DELETE(dmx_tx_pin); tmp |= OUTPUT(dmx_tx_pin); } else { tmp &= MODER_DELETE(dmx_tx_pin); tmp |= ALTFUNC(dmx_tx_pin); } dmx_tx_port->MODER = tmp; } void dmx_init(uint8_t *data, uint32_t universe_length, GPIO_TypeDef *tx_port, uint8_t tx_pin, uint16_t dmx_delay, uint16_t dmx_break_len, uint16_t break_pause) { dmx_tx_pin = tx_pin; dmx_tx_port = tx_port; dmx_data_ptr = data; dmx_tx_break_len = dmx_break_len; dmx_tx_break_pause = break_pause; /* Enable UART1 and TIM14 clock */ RCC->APB2ENR |= RCC_APB2ENR_USART1EN; RCC->APB1ENR |= RCC_APB1ENR_TIM14EN; /* Enable DMA clock */ RCC->AHBENR |= RCC_AHBENR_DMAEN; /* Set baudrate: 48MHz / 250k = 129 */ USART1->BRR = 192u; /* Two stop bits */ USART1->CR2 = USART_CR2_STOP_1; /* Transmitter enable, USART enable */ USART1->CR1 = USART_CR1_TE | USART_CR1_UE; /* Configure TIM14 to count in 10 us steps */ TIM14->PSC = 480u; /* Configure the reload value. Must be higher or equal to 200 */ if (dmx_delay < 2000) dmx_delay = 2000; TIM14->ARR = dmx_delay - 1; /* Enable TIM14 interrupt on update */ TIM14->DIER = TIM_DIER_UIE | TIM_DIER_CC1IE; NVIC_EnableIRQ(TIM14_IRQn); } void dmx_stream_start(void) { tx_state = DMX_TX_IDLE; TIM14->CR1 |= TIM_CR1_CEN; } void dmx_stream_stop(void) { tx_state = DMX_TX_OFF; TIM14->CR1 &= ~TIM_CR1_CEN; DMA1_Channel2->CCR = 0ul; __DSB(); USART1->CR3 = 0ul; } void TIM14_IRQHandler(void) { /* Clear interrupt sources */ TIM14->SR = 0; /* Start the break sequence if idle */ switch (tx_state) { case DMX_TX_IDLE: tx_state = DMX_TX_BREAK; /* Disable the DMA transfer */ USART1->CR3 = 0ul; TIM14->CCR1 = dmx_tx_break_len; /* Send break */ dmx_break(true); break; case DMX_TX_BREAK: /* Stop break pulse */ dmx_break(false); TIM14->CCR1 = dmx_tx_break_len + dmx_tx_break_pause; tx_state = DMX_TX_BREAK_PAUSE; break; case DMX_TX_BREAK_PAUSE: tx_state = DMX_TX_IDLE; break; default: break; } }