AnsweredAssumed Answered

STM32F4 USART2 TX using DMA (with StdPeriph_Driver)

Question asked by laurijssen.dennis on Sep 22, 2015
Latest reply on Sep 23, 2015 by laurijssen.dennis
Hello all,

I've been working on this STM32 project with my STM32407 discovery board. In this project I want to trigger a triple simultaneous ADC conversion with an external pin (PD14), once the DMA2 buffer is full this should trigger the USART2 to transfer the data to my computer using DMA1. After quite a bit of tinkering I managed to get this working up until the USART data transfer. 
When debugging I get to see the Transfer Complete flag 6 bit being set, but the data does not show up in  my terminal program.

I am using this code in main.c:
/* Includes ------------------------------------------------------------------*/
#include "stm32f4_discovery.h"
#include <stdio.h>
#include <stdint.h>
 
#define ADC_CCR_ADDRESS    ((uint32_t)0x40012308)
#define NUM_SAMPLES 10
 
/** @addtogroup STM32F4xx_StdPeriph_Examples
  * @{
  */
 
/** @addtogroup ADC_DualModeRegulSimu
  * @{
  */
 
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint16_t aADCTripleConvertedValue[NUM_SAMPLES*3];
 
/* Private function prototypes -----------------------------------------------*/
static void DMA1_Config(void);
static void DMA2_Config(void);
static void GPIO_Config(void);
static void ADC1_CH7_Config(void);
static void ADC2_CH5_Config(void);
static void ADC3_CH3_Config(void);
static void TIM2_Config(void);
static void USART2_Config(void);
 
void EXTILine14_Config(void);
void NVIC_Configuration(void);
 
/* Private functions ---------------------------------------------------------*/
 
/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
 
  /* Enable peripheral clocks *************************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
  
   
  TIM2_Config();
   
  /* ADCs configuration ------------------------------------------------------*/
  /* Configure ADC Channel 3, 5, 7 pin as analog input */
  GPIO_Config();
   
  USART2_Config();
   
  /* ADC Common Init */
  ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_RegSimult;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);
 
  /* ADC1 regular channel 7 configuration */
  ADC1_CH7_Config();
 
  /* ADC2 regular channel 5 configuration */
  ADC2_CH5_Config();
   
  /* ADC3 regular channel 3 configuration */
  ADC3_CH3_Config();
 
  STM_EVAL_LEDInit(LED5);
  STM_EVAL_LEDInit(LED3);
  STM_EVAL_LEDInit(LED4);
   
  /* Enable DMA request after last transfer (Multi-ADC mode) */
  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
 
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);
 
  /* Enable ADC2 */
  ADC_Cmd(ADC2, ENABLE);
   
  /* Enable ADC3 */
  ADC_Cmd(ADC3, ENABLE);
   
  /* DMA2 Stream0 channel0 configuration **************************************/
  DMA1_Config();
  DMA2_Config();
   
  /* Start ADC1 Software Conversion */
  ADC_SoftwareStartConv(ADC1);
   
   
  EXTILine14_Config();
  NVIC_Configuration();
   
  /* Generate software interrupt: simulate a rising edge applied on EXTI14 line */
  EXTI_GenerateSWInterrupt(EXTI_Line14);
 
   
  while (1)
  {
  }
}
 
 
 
/**************************************************************************************/
 
/**
  * @brief  ADC1 regular channels 10 and 11 configuration
  * @param  None
  * @retval None
  */
static void ADC1_CH7_Config(void)
{
  ADC_InitTypeDef ADC_InitStructure;
 
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC1, &ADC_InitStructure);
 
  /* ADC1 regular channel 7 configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_3Cycles);
}
 
/**************************************************************************************/
 
/**
  * @brief  ADC2 regular channels 11, 12 configuration
  * @param  None
  * @retval None
  */
static void ADC2_CH5_Config(void)
{
  ADC_InitTypeDef ADC_InitStructure;
 
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC2, &ADC_InitStructure);
 
  /* ADC2 regular channel 5 configuration */
  ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_3Cycles);
}
 
/**************************************************************************************/
 
static void ADC3_CH3_Config(void)
{
  ADC_InitTypeDef ADC_InitStructure;
 
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADC3, &ADC_InitStructure);
 
  /* ADC2 regular channel 3 configuration */
  ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 1, ADC_SampleTime_3Cycles);
}
 
/**************************************************************************************/
 
static void TIM2_Config(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  
  /* Time base configuration */
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
  TIM_TimeBaseStructure.TIM_Period = (84000000 / 500000) - 1; // 500 KHz, from 84 MHz TIM2CLK (ie APB1 = HCLK/4, TIM2CLK = HCLK/2)
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  
  /* TIM2 TRGO selection */
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); // ADC_ExternalTrigConv_T2_TRGO
  
  /* TIM2 enable counter */
  //TIM_Cmd(TIM2, ENABLE);
  TIM_Cmd(TIM2, DISABLE);
}
 
/**************************************************************************************/
 
static void USART2_Config(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_RTS_CTS;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  
  /* USART configuration */
  USART_Init(USART2, &USART_InitStructure);
  
  /* Enable the USART2 */
  USART_Cmd(USART2, ENABLE);
}
 
/**************************************************************************************/
 
/**
  * @brief  DMA Configuration
  * @param  None
  * @retval None
  */
static void DMA2_Config(void)
{
  DMA_InitTypeDef DMA_InitStructure;
  DMA_Cmd(DMA2_Stream0, DISABLE);
  DMA_DeInit(DMA2_Stream0);
 
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCTripleConvertedValue;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CCR_ADDRESS;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = NUM_SAMPLES*3;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  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_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
 
  /* Enable DMA Stream Transfer Complete interrupt */
  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);
   
  /* DMA2_Stream0 enable */
  DMA_Cmd(DMA2_Stream0, ENABLE);
}
 
/**************************************************************************************/
 
static void DMA1_Config(void)
{
  DMA_InitTypeDef DMA_InitStructure;
 
  DMA_InitStructure.DMA_Channel = DMA_Channel_4;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCTripleConvertedValue;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  DMA_InitStructure.DMA_BufferSize = NUM_SAMPLES*3;
  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_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;        
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA1_Stream6, &DMA_InitStructure);
 
   
  /* Enable the USART Tx DMA request */
  USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
   
  /* Enable DMA Stream Transfer Complete interrupt */
  DMA_ITConfig(DMA1_Stream6, DMA_IT_TC, ENABLE);
   
  /* DMA1_Stream6 enable */
  DMA_Cmd(DMA1_Stream6, ENABLE);
}
 
/**************************************************************************************/
 
/**
  * @brief Configure ADC Channels 3, 5, 7 pins as analog inputs
  * @param  None
  * @retval None
  */
static void GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  /* ADC Channel 3 -> PA3
     ADC Channel 5 -> PA5
     ADC Channel 7 -> PA7
  */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_5 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  /* Configure USART Tx as alternate function pull up */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  // PA2 USART2.TX
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /* Configure USART Tx as alternate function pull up */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; // PD6 USART2.RX
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
   
//  /* Configure USART CTS/RTS as alternate function pull up */
//  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // PA0 CTS PA1 RTS USART2
//  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
//  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
//  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
//  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  /* Configure PD14 pin as input floating */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
}
 
/**************************************************************************************/
 
void EXTILine14_Config(void)
  EXTI_InitTypeDef   EXTI_InitStructure;
 
  /* Enable SYSCFG clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
 
  /* Connect EXTI Line14 to PD14 pin */
  SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOD, EXTI_PinSource14);
 
  /* Configure EXTI Line14 */
  EXTI_InitStructure.EXTI_Line = EXTI_Line14;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
 
}
 
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
   
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* Enable the DMA Stream IRQ Channel */
  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
   
  /* Enable the DMA Stream IRQ Channel */
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream6_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
   
   
  /* Enable and set EXTI Line14 Interrupt to the lowest priority */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

and I have added this to my stm32f4xxit.c file:
void DMA2_Stream0_IRQHandler(void)
{
  /* Clear DMA Stream Transfer Complete interrupt pending bit */
  if ( DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0) )
  {
    /* Toggle LED3: End of Transfer */
    STM_EVAL_LEDToggle(LED3);
    TIM_Cmd(TIM2, DISABLE);
    DMA_Cmd(DMA1_Stream6, ENABLE);
     
     
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
  }
}
 
void DMA1_Stream6_IRQHandler(void)
{
  /* Clear DMA Stream Transfer Complete interrupt pending bit */
  if ( DMA_GetITStatus(DMA1_Stream6, DMA_IT_TCIF6) )
  {
    /* Toggle LED5: End of Transfer */
    STM_EVAL_LEDToggle(LED5);
    DMA_Cmd(DMA1_Stream6, DISABLE);
     
    DMA_ClearITPendingBit(DMA1_Stream6, DMA_IT_TCIF6);
  }
}
 
/**
  * @brief  This function handles External line 14 interrupt request.
  * @param  None
  * @retval None
  */
void EXTI15_10_IRQHandler(void)
{
  if(EXTI_GetITStatus(EXTI_Line14) != RESET)
  {
    /* Toggle LED4 */
    STM_EVAL_LEDToggle(LED4);
    TIM_Cmd(TIM2, ENABLE);
     
    /* Clear the EXTI line 14 pending bit */
    EXTI_ClearITPendingBit(EXTI_Line14);
  }
}

Would anyone happen to know what I am doing wrong? I presume that since I am using the DMA streams, my while loop can remain empty...

Best regards,

Dennis

Outcomes