Friday, April 3, 2020

ADC with DMA STM32 | Example code STM32 with Std Lib

UART Protocol – Rover Robotics
@par Example Description 

This example describes how to use the ADC3 and DMA to transfer continuously 
converted data from ADC3 to memory.
The ADC3 is configured to convert continuously channel7.
Each time an end of conversion occurs the DMA transfers, in circular mode, the
converted data from ADC3 DR register to the uhADCxConvertedValue variable.

In this example, the system clock is 168MHz, APB2 = 84MHz and ADC clock = APB2/2.
Since ADC3 clock is 42 MHz and sampling time is set to 3 cycles, the conversion
time to 12bit data is 12 cycles so the total conversion time is (12+3)/42= 0.36us(2.4Msps).

User can vary the ADC3 channel7 voltage using the Eval Board potentiometer
The converted voltage is displayed on the Eval Board LCD (when the define USE_LCD
is enabled in main.h)


@par Directory contents 

  - ADC/ADC_DMA/system_stm32f4xx.c   STM32F4xx system clock configuration file
  - ADC/ADC_DMA/stm32f4xx_conf.h     Library Configuration file
  - ADC/ADC_DMA/stm32f4xx_it.c       Interrupt handlers
  - ADC/ADC_DMA/stm32f4xx_it.h       Interrupt handlers header file
  - ADC/ADC_DMA/main.c               Main program
  - ADC/ADC_DMA/main.h               Main program header file


1. main.h
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __MAIN_H
#define __MAIN_H

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include <stdio.h>

#if defined (USE_STM324xG_EVAL)
  #include "stm324xg_eval.h"
  #include "stm324xg_eval_lcd.h"

#elif defined (USE_STM324x7I_EVAL)
  #include "stm324x7i_eval.h"
  #include "stm324x7i_eval_lcd.h"

#else
 #error "Please select first the Evaluation board used in your application (in Project Options)"
#endif

/* Private define ------------------------------------------------------------*/
/* used to display the ADC converted value on LCD */
#define USE_LCD
  /* if you are not using the LCD, you can monitor the converted value by adding
     the variable "uhADCxConvertedValue" to the debugger watch window */

/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
#if defined (USE_STM324xG_EVAL)

  #define FOOTER_MESSAGE    " ADC conversion w/DMA transfer example  "
  #define CONFIG1_MESSAGE   "ADC Ch7 Conv @2.4Msps"
  #define CONFIG2_MESSAGE   "  Turn RV1(PF.09)    "
  #define CONFIG3_MESSAGE   "   Potentiometer     "

  #define ADCx                     ADC3
  #define ADC_CHANNEL              ADC_Channel_7
  #define ADCx_CLK                 RCC_APB2Periph_ADC3
  #define ADCx_CHANNEL_GPIO_CLK    RCC_AHB1Periph_GPIOF
  #define GPIO_PIN                 GPIO_Pin_9
  #define GPIO_PORT                GPIOF
  #define DMA_CHANNELx             DMA_Channel_2
  #define DMA_STREAMx              DMA2_Stream0
  #define ADCx_DR_ADDRESS          ((uint32_t)0x4001224C)


#else /* defined (USE_STM324x7I_EVAL)*/

  #define FOOTER_MESSAGE    " ADC conversion w/DMA transfer example  "
  #define CONFIG1_MESSAGE   "ADC Ch7 Conv @2.4Msps"
  #define CONFIG2_MESSAGE   "  Turn RV1(PF.09)    "
  #define CONFIG3_MESSAGE   "   Potentiometer     "

  #define ADCx                     ADC3
  #define ADC_CHANNEL              ADC_Channel_7
  #define ADCx_CLK                 RCC_APB2Periph_ADC3
  #define ADCx_CHANNEL_GPIO_CLK    RCC_AHB1Periph_GPIOF
  #define GPIO_PIN                 GPIO_Pin_9
  #define GPIO_PORT                GPIOF
  #define DMA_CHANNELx             DMA_Channel_2
  #define DMA_STREAMx              DMA2_Stream0
  #define ADCx_DR_ADDRESS          ((uint32_t)0x4001224C)
#endif
/* Exported functions ------------------------------------------------------- */

#endif /* __MAIN_H */

2. main.c
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/** @addtogroup STM32F4xx_StdPeriph_Examples
  * @{
  */

/** @addtogroup ADC_DMA
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
__IO uint16_t uhADCxConvertedValue = 0;
__IO uint32_t uwADCxConvertedVoltage = 0;

/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
static void ADC_Config(void);

#ifdef USE_LCD
static void Display_Init(void);
static void Display(void);
#endif /* USE_LCD */

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
  /*!< At this stage the microcontroller clock setting is already configured,
       this is done through SystemInit() function which is called from startup
       files (startup_stm32f40xx.s/startup_stm32f427x.s) before to branch to
       application main.
       To reconfigure the default setting of SystemInit() function, refer to
       system_stm32f4xx.c file
     */

#ifdef USE_LCD
  /* LCD Display init  */
  Display_Init();
#endif

  /* ADC configuration */
  ADC_Config();

  /* Start ADC Software Conversion */
  ADC_SoftwareStartConv(ADCx);

  while (1)
  {
    uwADCxConvertedVoltage = uhADCxConvertedValue *3300/0xFFF;
#ifdef USE_LCD
  /* Display ADCx converted value on LCD */
    Display();
#endif
  }
}

/**
  * @brief  ADC3 channel07 with DMA configuration
  * @note   This function Configure the ADC peripheral
            1) Enable peripheral clocks
            2) DMA2_Stream0 channel2 configuration
            3) Configure ADC Channel7 pin as analog input
            4) Configure ADC3 Channel7
  * @param  None
  * @retval None
  */
static void ADC_Config(void)
{
  ADC_InitTypeDef       ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  DMA_InitTypeDef       DMA_InitStructure;
  GPIO_InitTypeDef      GPIO_InitStructure;

  /* Enable ADCx, DMA and GPIO clocks ****************************************/
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE);
  RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);


  /* DMA2 Stream0 channel2 configuration **************************************/
  DMA_InitStructure.DMA_Channel = DMA_CHANNELx;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADCx_DR_ADDRESS;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&uhADCxConvertedValue;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  DMA_InitStructure.DMA_BufferSize = 1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  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_Disable;       
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMA_STREAMx, &DMA_InitStructure);
  DMA_Cmd(DMA_STREAMx, ENABLE);

  /* Configure ADC3 Channel7 pin as analog input ******************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIO_PORT, &GPIO_InitStructure);

  /* ADC Common Init **********************************************************/
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);

  /* ADC3 Init ****************************************************************/
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADCx, &ADC_InitStructure);

  /* ADC3 regular channel7 configuration *************************************/
  ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_3Cycles);

 /* Enable DMA request after last transfer (Single-ADC mode) */
  ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE);

  /* Enable ADC3 DMA */
  ADC_DMACmd(ADCx, ENABLE);

  /* Enable ADC3 */
  ADC_Cmd(ADCx, ENABLE);
}

#ifdef USE_LCD
/**
  * @brief  Display ADC converted value on LCD
  * @param  None
  * @retval None
  */
static void Display(void)
{
  uint32_t uwVoltage = 0;
  uint32_t uwMVoltage = 0;
  uint8_t  aTextBuffer[50];

  uwVoltage = (uwADCxConvertedVoltage)/1000;
  uwMVoltage = (uwADCxConvertedVoltage%1000)/100;

  sprintf((char*)aTextBuffer,"   ADC = %d,%d V   ", uwVoltage, uwMVoltage);
  LCD_DisplayStringLine(LCD_LINE_6, aTextBuffer);
}

/**
  * @brief  Display Init (LCD)
  * @param  None
  * @retval None
  */
static void Display_Init(void)
{
  /* Initialize the LCD */
  LCD_Init();
  /* Clear the Background Layer */
  LCD_Clear(LCD_COLOR_WHITE);
  /* Set the LCD Back Color */
  LCD_SetBackColor(LCD_COLOR_BLUE);
  /* Set the LCD Text Color */
  LCD_SetTextColor(LCD_COLOR_WHITE);
  /* Set the LCD Text size */
  LCD_SetFont(&Font8x12);
  /* Display LCD Footer Message */
  LCD_DisplayStringLine(LCD_LINE_19, (uint8_t*)FOOTER_MESSAGE);

  /* Set the LCD Text size */
  LCD_SetFont(&Font16x24);
  /* Display Configuration Messages */
  LCD_DisplayStringLine(LCD_LINE_0, (uint8_t*)CONFIG1_MESSAGE);

  /* Set the LCD Back Color */
  LCD_SetBackColor(LCD_COLOR_WHITE);
  /* Set the LCD Text Color */
  LCD_SetTextColor(LCD_COLOR_BLUE);
  /* Display */
  LCD_DisplayStringLine(LCD_LINE_2, (uint8_t*)CONFIG2_MESSAGE);
  LCD_DisplayStringLine(LCD_LINE_4, (uint8_t*)CONFIG3_MESSAGE);
}
#endif /* USE_LCD */

No comments:

Post a Comment

Back to Top