cancel
Showing results for 
Search instead for 
Did you mean: 

UART with DMA mode

muhammad
Associate II
Posted on June 16, 2012 at 15:32

hi 

everyone

need help regarding UART with DMA mode,

i am using STM32F407 Discovery Board,

i want to configure UART4 with DMA, and want it to generate interrupt when DMA completes filling the memory. 

so should i configure the UART4's interrupt initializations also or only DMA interrupt initializations. I've attached my code. 

any help will be appreciated a lot. 

#selective-cut-n-paste #uart-usart-dma-interrupt
22 REPLIES 22
frankmeyer9
Associate II
Posted on June 16, 2012 at 18:44

...so should i configure the UART4's interrupt initializations also...

Not necessarily. You can configure an interrupt at DMA EOT (end-of-transmission).  An additional UART interrupt would be somehow redundant.

For 4800 bps, you do not necessarily need DMA transfer. The characters come in long intervals, by far enough time to process each character by interrupt.

To get DMA working as expected is a nice exercise, but it depends on your protocol/data structure, if it's the optimal method.

If the data come at irregular intervals, with low or average baud rate and have non-constant block length, interrupt processing seems more appropriate IMHO.

Posted on June 16, 2012 at 19:00

You probably don't want to be servicing the UART in both ways, the DMA is always going to hit the UART4->DR before you can possibly get to it via an interrupt. You just can't win that race.

Doing DMA Rx, and catching the RXNE interrupt might permit you to handle huge interrupt latencies, perhaps it would help if the CPU is stalling during a FLASH write, haven't tried it. I suspect the DMA would clear the pending IRQ.

In this case you'd let the DMA fetch the UART character, and then later when the RXNE interrupt gets called, you pluck the data out of the DMA buffer and leave the UART alone.

I can't see a case where using UART DMA Rx at 4800 baud solves more problems/complications than it creates. Care to elaborate?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
muhammad
Associate II
Posted on June 19, 2012 at 07:56

my objective for this effort is, to Enable DMA processor for handling UART, and generate an interrupt when my specified buffer size is filled by DMA individually, then main processor will service the interrupt and save the buffered data to another place.

frankmeyer9
Associate II
Posted on June 19, 2012 at 11:32

Can you make sure that all data transfered by DMA are belonging together semantically ?

I can hardly imagine that this is always true.

It would make more sense to process semantic blocks, i.e. commands, or whatever your protocoll defines. Otherwise, your buffer parsing code might get unnecessary complex.

Posted on June 19, 2012 at 19:34

// STM32 UART4 DMA RX (Tx PA.0, Rx PA.1) STM32F4 Discovery - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
/* --------------------------- System Clocks Configuration -----------------*/
/* UART4 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
/* GPIOA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* DMA1 clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*-------------------------- GPIO Configuration ----------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
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_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect USART pins to AF */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_UART4);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_UART4);
}
/**************************************************************************************/
void UART4_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
/* USARTx configuration ------------------------------------------------------*/
/* USARTx configured as follow:
- BaudRate = 4800 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 4800;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART4, &USART_InitStructure);
USART_Cmd(UART4, ENABLE);
}
/**************************************************************************************/
uint8_t Buffer[32];
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Stream2);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Receive
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
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_Init(DMA1_Stream2, &DMA_InitStructure);
/* Enable the USART Rx DMA request */
USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);
/* Enable DMA Stream Half Transfer and Transfer Complete interrupt */
DMA_ITConfig(DMA1_Stream2, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Stream2, DMA_IT_HT, ENABLE);
/* Enable the DMA RX Stream */
DMA_Cmd(DMA1_Stream2, ENABLE);
}
/**************************************************************************************/
void DMA1_Stream2_IRQHandler(void)
{
/* Test on DMA Stream Transfer Complete interrupt */
if (DMA_GetITStatus(DMA1_Stream2, DMA_IT_TCIF2))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_TCIF2);
USART_SendData(UART4, 'C');
}
/* Test on DMA Stream Half Transfer interrupt */
if (DMA_GetITStatus(DMA1_Stream2, DMA_IT_HTIF2))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_HTIF2);
USART_SendData(UART4, 'H');
}
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the Priority Group to 2 bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Enable the UART4 RX DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
UART4_Configuration();
DMA_Configuration();
while(USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET); // Wait for Empty
USART_SendData(UART4, '*');
while(1); // Don't want to exit
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
muhammad
Associate II
Posted on June 20, 2012 at 11:21

hi Clive and others

thanks a lot for your support and effort.

i achieve my objective successively.

i configure my full UART Rx+Tx with DMA

and access the max size of DMA.

pccmd
Associate II
Posted on November 21, 2012 at 05:51

Clive,

The Tx interrupt did not work until I changed the following to link to Tx not Rx.

USART_DMACmd(UART4, USART_DMAReq_Tx,

ENABLE

);

I also, changed to Stream 4 for the USART4_TX.

// STM32 UART4 DMA RX (Tx PA.0, Rx PA.1) STM32F4 Discovery - sourcer32@gmail.com
#include ''stm32f4_discovery.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
/* --------------------------- System Clocks Configuration -----------------*/
/* UART4 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4, ENABLE);
/* GPIOA clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* DMA1 clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*-------------------------- GPIO Configuration ----------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
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_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect USART pins to AF */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource0, GPIO_AF_UART4);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource1, GPIO_AF_UART4);
}
/**************************************************************************************/
void UART4_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
/* USARTx configuration ------------------------------------------------------*/
/* USARTx configured as follow:
- BaudRate = 4800 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 4800;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(UART4, &USART_InitStructure);
USART_Cmd(UART4, ENABLE);
}
/**************************************************************************************/
uint8_t Buffer[32];
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Stream2);
DMA_InitStructure.DMA_Channel = DMA_Channel_4;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Receive
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Buffer;
DMA_InitStructure.DMA_BufferSize = (uint16_t)sizeof(Buffer);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&UART4->DR;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
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_Init(DMA1_Stream2, &DMA_InitStructure);
/* Enable the USART Rx DMA request */
USART_DMACmd(UART4, USART_DMAReq_Rx, ENABLE);
/* Enable DMA Stream Half Transfer and Transfer Complete interrupt */
DMA_ITConfig(DMA1_Stream2, DMA_IT_TC, ENABLE);
DMA_ITConfig(DMA1_Stream2, DMA_IT_HT, ENABLE);
/* Enable the DMA RX Stream */
DMA_Cmd(DMA1_Stream2, ENABLE);
}
/**************************************************************************************/
void DMA1_Stream2_IRQHandler(void)
{
/* Test on DMA Stream Transfer Complete interrupt */
if (DMA_GetITStatus(DMA1_Stream2, DMA_IT_TCIF2))
{
/* Clear DMA Stream Transfer Complete interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_TCIF2);
USART_SendData(UART4, 'C');
}
/* Test on DMA Stream Half Transfer interrupt */
if (DMA_GetITStatus(DMA1_Stream2, DMA_IT_HTIF2))
{
/* Clear DMA Stream Half Transfer interrupt pending bit */
DMA_ClearITPendingBit(DMA1_Stream2, DMA_IT_HTIF2);
USART_SendData(UART4, 'H');
}
}
/**************************************************************************************/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure the Priority Group to 2 bits */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* Enable the UART4 RX DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
UART4_Configuration();
DMA_Configuration();
while(USART_GetFlagStatus(UART4, USART_FLAG_TXE) == RESET); // Wait for Empty
USART_SendData(UART4, '*');
while(1); // Don't want to exit
}

Posted on November 26, 2012 at 15:43

The Tx interrupt did not work until I changed the following to link to Tx not Rx.

Ok, it was only presented as an RX example, I've posted other TX, and RX+TX examples.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
tomv
Associate
Posted on September 24, 2013 at 22:26

Hi Clive1,

Could you give me a link to the RX+TX code you mention? 

Also, I've been looking some newer code and some of the DMA calls and options have changed.  Do you happen to have something that works with the newer libraries?  I believe these are 3.x.y.

TIA

--TV