cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 DMX-512 Receiver (with separate timer pin, DMA RX)

paul2399
Associate
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!
6 REPLIES 6
Posted on February 01, 2015 at 03:06

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?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
paul2399
Associate
Posted on February 01, 2015 at 21:36

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).
dave239955_st
Associate
Posted on March 23, 2015 at 08:43

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 :D

Let me tidy up my code a little bit, and I will post it here later tonight or tomorrow night

Dave

genis
Associate II
Posted on July 27, 2015 at 16:21

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?

Amel NASRI
ST Employee
Posted on July 28, 2015 at 11:37

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

https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Restart%20Rx%20USART%20%2b%20DMA%20in%20STM32L1

.

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.