137 lines
3.0 KiB
C
137 lines
3.0 KiB
C
#include <ring-light/dmx.h>
|
|
#include <stm32f0xx.h>
|
|
|
|
static uint32_t dmx_base_channel;
|
|
|
|
|
|
enum dmx_rx_state_enum {
|
|
DMX_RX_WAIT_FOR_BREAK = 0,
|
|
DMX_RX_DATA,
|
|
};
|
|
|
|
static volatile enum dmx_rx_state_enum dmx_state;
|
|
|
|
|
|
static volatile bool break_received;
|
|
|
|
/**
|
|
* @brief DMX data received. Contains the whole DMX universe including the first 0 byte.
|
|
* The controller does check the first byte to be zero.
|
|
*/
|
|
static volatile uint8_t dmx_channel_data[DMX_UNIVERSE_SIZE + 1];
|
|
|
|
void dmx_init(uint32_t base_channel)
|
|
{
|
|
int i;
|
|
volatile uint8_t *ptr;
|
|
|
|
for (i = 0, ptr = dmx_channel_data; i < DMX_USED_CHANNEL_COUNT; i++, ptr++) {
|
|
*ptr = 0u;
|
|
}
|
|
|
|
dmx_base_channel = base_channel;
|
|
break_received = false;
|
|
|
|
/* Enable GPIOA and USART1 clock */
|
|
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_DMAEN;
|
|
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;
|
|
|
|
/* Map USART1 RX to DMA Channel 3 */
|
|
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);
|
|
}
|
|
|
|
|
|
const uint8_t *dmx_get_data()
|
|
{
|
|
return (const uint8_t *)dmx_channel_data;
|
|
}
|
|
|
|
void USART1_IRQHandler(void)
|
|
{
|
|
uint32_t isr;
|
|
|
|
isr = USART1->ISR;
|
|
USART1->ICR = USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF;
|
|
|
|
if (isr & USART_ISR_FE) {
|
|
/* Frame error received. Start of DMX frame */
|
|
/* Flush RX data */
|
|
USART1->CR3 &= ~USART_CR3_DMAR;
|
|
USART1->RQR = USART_RQR_RXFRQ;
|
|
DMA1_Channel3->CCR &= ~DMA_CCR_EN;
|
|
while (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->RQR = USART_RQR_RXFRQ;
|
|
USART1->CR3 |= USART_CR3_DMAR;
|
|
break_received = true;
|
|
dmx_state = DMX_RX_DATA;
|
|
} else if (isr & USART_ISR_RXNE) {
|
|
if (dmx_state != DMX_RX_DATA) {
|
|
USART1->RQR = USART_RQR_RXFRQ;
|
|
}
|
|
}
|
|
|
|
__DSB();
|
|
}
|
|
|
|
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;
|
|
dmx_state = DMX_RX_WAIT_FOR_BREAK;
|
|
}
|
|
__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;
|
|
}
|