cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 USART2 per DMA Problem

robin2399
Associate II
Posted on August 30, 2012 at 16:41

I have a problem that maybe someone can help with. I've spend the last few days on this and I just don't understand why it's not working.

I have a STM32 where I want to send out a buffer over USART 2 using DMA to a RS485 chip that sends it to a Hyperterminal via FTDI cable. I had this working using USART without DMA... by just feeding the Register with the buffer one by one. So I know that the USART and the RS485 chip works. 

After inital problems i have gone to a simple example from ST Library and modified it but still can't get it to work. Here is my code.. I'm trying to continuosly send out data over USART2. 

The problem: It doesn't send at all... or only once.. and usually gets stuck here:

while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET)

Can anyone see what I'm doing wrong?

/* Includes ------------------------------------------------------------------*/

&sharpinclude ''stm32f10x.h''

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

&sharpdefine TxBufferSize2   (countof(TxBuffer2) - 1)

/* Private macro -------------------------------------------------------------*/

&sharpdefine countof(a)   (sizeof(a) / sizeof(*(a)))

/* Private variables ---------------------------------------------------------*/

USART_InitTypeDef USART_InitStructure;

uint8_t TxBuffer2[] = ''USART DMA Test Buffer\n'';

uint8_t RxBuffer1[TxBufferSize2];

/* Private function prototypes -----------------------------------------------*/

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);

void DMA_Configuration(void);

/* Private functions ---------------------------------------------------------*/

int main(void)

{

  /* System Clocks Configuration */

  RCC_Configuration();

      

  /* NVIC configuration */

  NVIC_Configuration();

  /* Configure the GPIO ports */

  GPIO_Configuration();

  /* Configure the DMA */

  DMA_Configuration();

 /* USART2 Initialization  */

  USART_InitStructure.USART_BaudRate = 115200;

  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_Tx;

 

 /* Configure USART2 */

  USART_Init( USART2, &USART_InitStructure);

 /* Disable the DMA Interrupts

   I do want to use the interrupts later 

     (that's the whole point) but I want

   to get it working without them first. */

  DMA_ITConfig( DMA1_Channel7, DMA_IT_TC|DMA_IT_HT|DMA_IT_TE, DISABLE) ;

  /* Enable USARTy DMA TX request */

  USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);

 

  /* Enable USART2 */

  USART_Cmd(USART2, ENABLE);

  while(1)

 {

  

  /* Do I need to clear these flags before sending? */

  DMA_ClearFlag(DMA1_FLAG_TC7);

  DMA_ClearFlag(DMA1_FLAG_HT7);

  DMA_ClearFlag(DMA1_FLAG_TE7);

  DMA_ClearITPendingBit( DMA1_IT_TC7);

  DMA_ClearITPendingBit( DMA1_IT_TE7);

  DMA_ClearITPendingBit( DMA1_IT_HT7);

  

  /* Enable USARTy DMA TX Channel

    Transmit should now start and usually 

    sends one time.   */

   DMA_Cmd(DMA1_Channel7, ENABLE);

   /* Wait until USARTy TX DMA1 Channel  Transfer Complete

     It gets stuck here. Why is the flag not set? */

   while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET)

   {

   }

 

  DMA_Cmd(DMA1_Channel7, DISABLE); //Do i need to this?

 }

}

void RCC_Configuration(void)

{   

  /* DMA clock enable */

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

  /* Enable GPIO clock */

  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

  /* Enable USART2 Clock */

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 

}

void GPIO_Configuration(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable the USART2 Pins Software Remapping */

  //GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); 

 

  /* Configure USART2 Tx as alternate function push-pull */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* UART  Direction */

  GPIO_InitStructure.GPIO_Pin     = GPIO_Pin_1;

  GPIO_InitStructure.GPIO_Speed   = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode    = GPIO_Mode_Out_PP;

  GPIO_Init(GPIOA, &GPIO_InitStructure);

 

 GPIOA->BSRR = GPIO_Pin_1; //Set Pin High..TX

}

void NVIC_Configuration(void)

{

   NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the USARTz Interrupt */

  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

void DMA_Configuration(void)

{

  DMA_InitTypeDef DMA_InitStructure;

 /* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */

  DMA_DeInit(DMA1_Channel7);

  DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404;

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

  DMA_InitStructure.DMA_BufferSize = TxBufferSize2;

  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_Normal;

  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

  DMA_Init(DMA1_Channel7, &DMA_InitStructure);

 

}

#dma #stm32-usart-interrupt-dma #dma-tc-interrupt-usart
7 REPLIES 7
Posted on August 30, 2012 at 17:48

I think it's because you need to program DMA for each transfer.

This works for USART1 on a VLDiscovery, I don't have USART2 wired up.

// STM32 USART DMA TX (USART1 TX PA.09) VLDiscovery - sourcer32@gmail.com
#include ''stm32F10x.h''
#include ''STM32vldiscovery.h''
char TxString[] = ''The quick brown fox jumps over the lazy dog

'';
/**************************************************************************************/
void RCC_Configuration(void)
{
/* Enable DMA clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
/* Enable GPIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* Enable UART clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // PA.09 USART1.TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PA.10 USART1.RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/**************************************************************************************/
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
/* USART resources configuration (Clock, GPIO pins and USART registers) ----*/
/* USART configured as follow:
- BaudRate = 115200 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 = 115200;
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 configuration */
USART_Init(USART1, &USART_InitStructure);
/* Enable the USART1 */
USART_Cmd(USART1, ENABLE);
}
/**************************************************************************************/
void DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel4);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxString;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = sizeof(TxString) - 1;
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_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel4, &DMA_InitStructure);
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
USART_Configuration();
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
while(1)
{
DMA_Configuration();
DMA_Cmd(DMA1_Channel4, ENABLE);
while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);
}
}
/**************************************************************************************/
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**************************************************************************************/

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
robin2399
Associate II
Posted on August 31, 2012 at 09:44

Thank you kind sir! You are a hero! - It works now 🙂

I wasted so much time on this - and i still don't understand why it's necessary to reinitialize the dma before each transmit... but it works for now.

robin2399
Associate II
Posted on August 31, 2012 at 15:39

Ok next problem...

Now I want to use the interrupt - but every time I set it up like this:

/* Enable the DMA Channel 7 Interrupt */ 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure);

the program gets stuck and the Transmit Complete Flag doesen't get set anymore. Does anyone see my fault. All I want to do.. is to start sending using the DMA .. and then use the TC interrupt to toggle an output on the board. The interrupt never comes though. Here is my code:

/* Includes ------------------------------------------------------------------*/ 
#include ''stm32f10x.h'' 
/* Private typedef -----------------------------------------------------------*/ 
/* Private define ------------------------------------------------------------*/ 
#define TxBufferSize2 (countof(TxBuffer2) - 1) 
/* Private macro -------------------------------------------------------------*/ 
#define countof(a) (sizeof(a) / sizeof(*(a))) 
/* Private variables ---------------------------------------------------------*/ 
USART_InitTypeDef USART_InitStructure; 
uint8_t TxBuffer2[] = ''USART DMA Test Buffer
''; 
uint8_t RxBuffer1[TxBufferSize2]; 
/* Private function prototypes -----------------------------------------------*/ 
void RCC_Configuration(void); 
void GPIO_Configuration(void); 
void NVIC_Configuration(void); 
void DMA_Configuration(void); 
void USART_Configuration( void ); 
void delay( void ); 
/* Private functions ---------------------------------------------------------*/ 
int main(void) 
{ 
RCC_Configuration(); 
NVIC_Configuration(); 
GPIO_Configuration(); 
USART_Configuration(); 
/* Enable USART2 DMA TX request */ 
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); 
while(1) 
{ 
DMA_Configuration(); 
DMA_Cmd(DMA1_Channel7, ENABLE); 
while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET); 
delay(); 
} 
} 
void delay( void ) 
{ 
uint32_t i = 0xFFFFF; 
while( i > 0 ) 
{ 
i--; 
} 
} 
void DMA1_Channel7_IRQHandler(void) 
{ 
// Never comes here ! 
if( DMA_GetITStatus(DMA1_IT_TC7) == SET ) 
{ 
DMA_ClearITPendingBit( DMA1_IT_TC7); 
} 
if( DMA_GetITStatus(DMA1_IT_TE7) == SET ) 
{ 
DMA_ClearITPendingBit( DMA1_IT_TE7); 
} 
} 
void USART_Configuration( void ) 
{ 
/* USART2 Initialization */ 
USART_InitStructure.USART_BaudRate = 115200; 
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_Tx; 
/* Configure USART2 */ 
USART_Init( USART2, &USART_InitStructure); 
/* Enable USART2 */ 
USART_Cmd(USART2, ENABLE); 
} 
void RCC_Configuration(void) 
{ 
/* DMA clock enable */ 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
/* Enable GPIO clock */ 
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE); 
/* Enable USART2 Clock */ 
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); 
} 
void GPIO_Configuration(void) 
{ 
GPIO_InitTypeDef GPIO_InitStructure; 
/* Enable the USART2 Pins Software Remapping */ 
//GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); 
/* Configure USART2 Tx as alternate function push-pull */ 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
GPIO_Init(GPIOA, &GPIO_InitStructure); 
/* UART Direction */ 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; 
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
GPIO_Init(GPIOA, &GPIO_InitStructure); 
GPIOA->BSRR = GPIO_Pin_1; //Set Pin High..TX 
} 
void NVIC_Configuration(void) 
{ 
NVIC_InitTypeDef NVIC_InitStructure; 
/* Enable the USARTz Interrupt */ 
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure); 
/* Enable the DMA Channel 7 Interrupt */ 
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel7_IRQn; 
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
NVIC_Init(&NVIC_InitStructure); 
} 
void DMA_Configuration(void) 
{ 
DMA_InitTypeDef DMA_InitStructure; 
DMA_DeInit(DMA1_Channel7); 
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40004404; 
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2; 
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; 
DMA_InitStructure.DMA_BufferSize = TxBufferSize2; 
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_Normal; 
DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 
DMA_Init(DMA1_Channel7, &DMA_InitStructure); 
//Enable the transfer complete interrupt! 
DMA_ITConfig( DMA1_Channel7, DMA_IT_TC, ENABLE) ; 
} 

jpeacock2399
Associate II
Posted on August 31, 2012 at 15:57

DMA has two modes.  You are using the ''normal'' mode, which is a one-shot transfer for a fixed length.  DMA stops at the end of the transfer.

The other mode is ''circular'', where DMA constantly transfers data to/from a buffer.  At the end of the buffer the DMA channel wraps back to the start.  The problem with this mode is underflow...making sure the buffer always has enough data for the DMA transfer.  This is why there is an HT (Half Transfer) flag.  When half the DMA buffer is exhausted an interrupt signals that more data must be placed in that section of the buffer.

This is what's known as ''ping pong''.  One half of the buffer is active for DMA and can't be touched.  The other half is filled by the application.  DMA bounces back and forth (like a ping pong ball) between the two halves.

The far more complicated alternative to the HT flag is to track the DMA pointer by the remaining data register, filling memory with new data as it is drained by DMA transfers.  You have to take into account buffered I/O and DMA FIFO's if you are using an M4 (STM32F3xx/STM32F4xx) or M3 rev 2 (STM32F2xx).

  Jack Peacock

robin2399
Associate II
Posted on August 31, 2012 at 16:42

Thanks Jack..

I am actually just trying to send one message... but repeated many times.

I think the problem is with my NVIC setup. The Interrupt is enabled but then jumps somewhere where there is no code.

I'm not sure yet why this happens.

r_s_1
Associate
Posted on December 21, 2013 at 23:47

i encountred the same problem DMA is working only with usart1 but not all channel that's why i tried all channel and it's finally working with channel6 i don't know if its a problem or a configuration range in STM

Posted on December 22, 2013 at 01:48

Something you'd expect to find in a Reference Manual?

0690X000006052kQAA.png

From the STM32F1xx one

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..