182 lines
3.9 KiB
C
182 lines
3.9 KiB
C
#include "stm32f030x6.h"
|
|
#include <dmx.h>
|
|
#include <stdint.h>
|
|
#include <stm32f0xx.h>
|
|
#include <stdbool.h>
|
|
#include <stm-periph/stm32-gpio-macros.h>
|
|
|
|
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;
|
|
|
|
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_universe_length = universe_length;
|
|
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, trawsnmission complete interrupt */
|
|
USART1->CR1 = USART_CR1_TE | USART_CR1_UE | USART_CR1_TCIE;
|
|
|
|
|
|
/* Configure TIM14 to count in 10 us steps */
|
|
TIM14->PSC = 480u - 1u;
|
|
|
|
/* 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);
|
|
|
|
/* Enable Interrupts for USART and DMA */
|
|
NVIC_EnableIRQ(USART1_IRQn);
|
|
NVIC_EnableIRQ(DMA1_Channel2_3_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)
|
|
{
|
|
uint32_t sr;
|
|
|
|
sr = TIM14->SR;
|
|
|
|
/* Clear interrupt sources */
|
|
TIM14->SR = 0;
|
|
|
|
/* Start the break sequence if idle */
|
|
switch (tx_state) {
|
|
case DMX_TX_IDLE:
|
|
if (!(sr & TIM_SR_UIF))
|
|
break;
|
|
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:
|
|
/* Send null byte */
|
|
tx_state = DMX_TX_NULLBYTE;
|
|
USART1->TDR = 0x00;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
enum dmx_tx_state dmx_tx_get_current_state(void)
|
|
{
|
|
return tx_state;
|
|
}
|
|
|
|
void USART1_IRQHandler(void)
|
|
{
|
|
uint32_t isr;
|
|
|
|
isr = USART1->ISR;
|
|
|
|
/* Clear interrupt flag */
|
|
USART1->ICR = USART_ICR_TCCF;
|
|
|
|
if (isr & USART_ISR_TC) {
|
|
if (tx_state == DMX_TX_NULLBYTE) {
|
|
/* Null byte transferred. Go to data state and setup DMA */
|
|
tx_state = DMX_TX_DATA;
|
|
USART1->CR3 |= USART_CR3_DMAT;
|
|
|
|
DMA1_Channel2->CPAR = (uint32_t)&USART1->TDR;
|
|
DMA1_Channel2->CMAR = (uint32_t)dmx_data_ptr;
|
|
DMA1_Channel2->CNDTR = dmx_universe_length & 0xFFFF;
|
|
DMA1_Channel2->CCR = DMA_CCR_PL_1 | DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE | DMA_CCR_EN;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DMA_CH2_3_DMA2_CH1_2_IRQHandler(void)
|
|
{
|
|
uint32_t isr;
|
|
|
|
isr = DMA1->ISR;
|
|
DMA1->IFCR = isr & DMA_ISR_TCIF2;
|
|
|
|
if (isr & DMA_ISR_TCIF2) {
|
|
/* Channnel 2 trasnfer complete. Universe trasnferred */
|
|
tx_state = DMX_TX_IDLE;
|
|
DMA1_Channel2->CCR = 0u;
|
|
USART1->CR3 &= ~USART_CR3_DMAT;
|
|
}
|
|
} |