Question
STM32F4 DMX-512 Receiver (with separate timer pin, DMA RX)
Posted on February 01, 2015 at 02:02
I have spent the last couple days debugging the behaviour of a DMX-512 driver using the older STM32 STDPERIPH libraries.
In this implementation, I am using USART1/DMA for data rx, and TIM4 ch1 in PWM input capture mode to detect the 88usec break before USART data can be received. I simply joined the two pins together in push-pull floating mode.I made a simple test case using an RTOS, and I can confirm the hardware seems fine for this case. For the STDPERIPH version, the timer for BREAK detection works fine, and *should* trigger a DMA transfer for the expected 512+1 bytes (513 total size). Confirmed with logic analyzer, it can toggle a pin after each BREAK is detected, but before the first USART start bit is received. MY PROBLEM IS: the DMA and/or the USART does not seem to be responding. Same configuration; USART works fine in TX mode with DMA transfers (250kbaud, 2 stop bits, etc. as per DMX standard), although I do not have an example that generates a BREAK before TX. Attached is the DMX rx driver code:
// Private typedef -------------------------------------------------------------
// Private define --------------------------------------------------------------
// Private macro ---------------------------------------------------------------
// Private variables -----------------------------------------------------------
uint8_t DMX_rx_mark_overflow = 0;
uint8_t DMX_rx_transferInProgress = 0;
uint8_t DMX_rxBuffer[513];
// Private function prototypes -------------------------------------------------
static
void
DMX_RCC_Config(
void
);
static
void
DMX_GPIO_Config(
void
);
static
void
DMX_NVIC_Config(
void
);
static
void
DMX_USART_Config(
void
);
static
void
DMX_RX_DMA_Config(
void
);
static
void
DMX_TIM_Config(
void
);
// Private functions -----------------------------------------------------------
void
DMX_Config(
void
)
{
DMX_RCC_Config();
DMX_NVIC_Config();
DMX_GPIO_Config();
DMX_USART_Config();
DMX_TIM_Config();
// Enable TIM4 counter
TIM_Cmd(TIM4, ENABLE);
// Enable USART
USART_Cmd(USART1, ENABLE);
DMX_RX_DMA_Config();
// Enable the USART Rx DMA request
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
}
static
void
DMX_RCC_Config(
void
)
{
// Enable GPIO clocks
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
// USART1 clock enable
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
// DMA clock enable
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
// TIM4 clock enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
}
static
void
DMX_GPIO_Config(
void
)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
// DMX RX pin configuration
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Connect DMX RX pin to AF
GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
// DMX MARK pin configuration
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Connect DMX MARK pin to AF
GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_TIM4);
// debug MARK pin configuration
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
static
void
DMX_NVIC_Config(
void
)
{
NVIC_InitTypeDef NVIC_InitStructure;
// Enable the USART1 global Interrupt
// Configure the Priority Group to 2 bits
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// Enable the UART RX DMA Interrupt
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable the TIM4 global Interrupt
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static
void
DMX_USART_Config(
void
)
{
USART_InitTypeDef DMX_InitStructure;
// Enable the USART OverSampling by 8
USART_OverSampling8Cmd(USART1, ENABLE);
DMX_InitStructure.USART_BaudRate = 250000;
DMX_InitStructure.USART_WordLength = USART_WordLength_8b;
DMX_InitStructure.USART_StopBits = USART_StopBits_2;
DMX_InitStructure.USART_Parity = USART_Parity_No;
DMX_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
DMX_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &DMX_InitStructure);
}
static
void
DMX_RX_DMA_Config(
void
)
{
DMA_InitTypeDef DMA_InitStructure;
// Configure DMA controller to manage TX DMA requests
// first make sure we are using the default values
DMA_StructInit(&DMA_InitStructure);
// Configure DMA controller to manage USART TX and RX DMA request ------------
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
//DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
// RX Stream -----------------------------------------------------------------
DMA_DeInit(DMA2_Stream2);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DMX_rxBuffer;
DMA_InitStructure.DMA_BufferSize =
sizeof
(DMX_rxBuffer);
DMA_Init(DMA2_Stream2, &DMA_InitStructure);
DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA2_Stream2, DMA_IT_HT, ENABLE);
}
static
void
DMX_TIM_Config(
void
)
{
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// TIM4 configuration
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_PWMIConfig(TIM4, &TIM_ICInitStructure);
// Select the TIM4 Input Trigger
TIM_SelectInputTrigger(TIM4, TIM_TS_TI1FP1);
// Select the slave Mode: Reset Mode
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);
TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);
// Only generate Update Event on counter overflow
TIM_UpdateRequestConfig(TIM4, TIM_UpdateSource_Regular);
// Enable the DMX_MARK_TIM_IT_CCx Interrupt Requests
TIM_ITConfig(TIM4, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_Update, ENABLE);
}
int
DMX_is_recv_done()
{
return
(DMX_rx_transferInProgress == 0);
}
void
TIM4_IRQHandler(
void
)
{
if
(TIM_GetITStatus(TIM4, TIM_IT_CC1))
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC1);
}
if
(TIM_GetITStatus(TIM4, TIM_IT_CC2))
{
TIM_ClearITPendingBit(TIM4, TIM_IT_CC2);
if
(DMX_rx_mark_overflow == 1)
{
DMX_rx_mark_overflow = 0;
}
else
{
uint16_t pulseValue = TIM_GetCapture2(TIM4);
if
((pulseValue > 8800))
{
DMX_RX_DMA_Config();
DMA_ClearFlag(DMA2_Stream2, DMA_FLAG_TCIF2);
DMA_Cmd(DMA2_Stream2, ENABLE);
DMX_rx_transferInProgress = 1;
//GPIO_ToggleBits(GPIOA, GPIO_Pin_8);
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
}
}
}
if
(TIM_GetITStatus(TIM4, TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
DMX_rx_mark_overflow = 1;
}
}
void
DMA2_Stream2_IRQHandler(
void
)
{
if
(DMA_GetITStatus(DMA2_Stream2, DMA_IT_TCIF2))
{
DMA_ClearITPendingBit(DMA2_Stream2, DMA_IT_TCIF2);
DMX_rx_transferInProgress = 0;
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_RESET);
}
}
Thanks in advance for your help!