2015-01-31 05:02 PM
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!
2015-01-31 06:06 PM
Looks reasonable enough, probably want to decide if you want the HT interrupt, and to service it.
Does the USART Rx work in interrupt/polling mode?2015-02-01 12:36 PM
Hi clive,
Servicing DMA RX HT interrupt (just attempt to toggle a pin) has no effect, DMA RX is still non functioning. Yes, just checked and USART RX does work correctly in interrupt mode. Only changes were removing calls to my DMX_RX_DMA_Config() function and not calling USART_DMACmd(), insteadadding:USART_ITConfig(DMX_USARTx, USART_IT_RXNE, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
// Enable the UART TX DMA Interrupt
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
and a suitable USART1_IRQHandler to catchUSART_IT_RXNE and copy USART1->DR to the DMX_rxBuffer array.
Any ideas on the DMA RX configuration specifics? I also triedDMA_Channel_4/DMA2_Stream5 as ref. guide says that is also valid for USART1_RX, but it is still not working.
As well, I tried firing DMA RX without re-configuration for each transfer (I know it is recommended, but in the past I recall being able to run the same transfer repeatedly without configuration.) With re-configuration, the transfer starts during the first start bit, without it fires during the detected pulse (well before any USART data).
2015-03-23 12:43 AM
Hi Paul and all,
OK, first post here, I'm sure it will be the first of many!I have some working code for DMX reception via DMA, but rather than wasting a separate timer, my code uses the USART framing error interrupt to synchronise reception. I have code written for AVR ( mega / xmega ) that uses FE to resync, and it works well, but its nice to have so many interuppts to play with with the stm32 :DLet me tidy up my code a little bit, and I will post it here later tonight or tomorrow nightDave2015-07-27 07:21 AM
I am experiencing a similar issue here. I am using an STM32L152. In my case, the first DMA Rx succeeds and the interrupt fires once, but never works a second time.
Did you manage to address your problem?2015-07-28 02:37 AM
Hiaguilar.genis,
How ''similar'' is your problem to the one described in this old discussion? What are you trying to do exactly? What is about your hardware? Are you using an example provided in ST packages or your own code? Please provide more details on your case in order to have more chance to get a helpful answer. -Mayla- Edit: I see some answers to my questions .To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.
2015-07-28 03:42 AM
Hi Mayla. It turned out to be a different problem. You can see the solution
. Thanks a lot.