2019-07-19 14:54:54 +01:00

538 lines
20 KiB
C

/**
******************************************************************************
* @file ADC/ADC_Sequencer/Src/main.c
* @author MCD Application Team
* @brief This example provides a short description of how to use the ADC
* peripheral with sequencer, to convert several channels.
* Channels converted are 1 channel on external pin and 2 internal
* channels (VrefInt and temperature sensor).
* Moreover, voltage and temperature are then computed.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/** @addtogroup STM32F1xx_HAL_Examples
* @{
*/
/** @addtogroup ADC_Sequencer
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define VDD_APPLI ((uint32_t) 3300) /* Value of analog voltage supply Vdda (unit: mV) */
#define RANGE_12BITS ((uint32_t) 4095) /* Max value with a full range of 12 bits */
#define USERBUTTON_CLICK_COUNT_MAX ((uint32_t) 4) /* Maximum value of variable "UserButtonClickCount" */
#define ADCCONVERTEDVALUES_BUFFER_SIZE ((uint32_t) 3) /* Size of array containing ADC converted values: set to ADC sequencer number of ranks converted, to have a rank in each address */
/* Internal temperature sensor: constants data used for indicative values in */
/* this example. Refer to device datasheet for min/typ/max values. */
/* For more accurate values, device should be calibrated on offset and slope */
/* for application temperature range. */
#define INTERNAL_TEMPSENSOR_V25 ((int32_t)1430) /* Internal temperature sensor, parameter V25 (unit: mV). Refer to device datasheet for min/typ/max values. */
#define INTERNAL_TEMPSENSOR_AVGSLOPE ((int32_t)4300) /* Internal temperature sensor, parameter Avg_Slope (unit: uV/DegCelsius). Refer to device datasheet for min/typ/max values. */ /* This calibration parameter is intended to calculate the actual VDDA from Vrefint ADC measurement. */
/* Private macro -------------------------------------------------------------*/
/**
* @brief Computation of temperature (unit: degree Celsius) from the internal
* temperature sensor measurement by ADC.
* Computation is using temperature sensor standard parameters (refer
* to device datasheet).
* Computation formula:
* Temperature = (VTS - V25)/Avg_Slope + 25
* with VTS = temperature sensor voltage
* Avg_Slope = temperature sensor slope (unit: uV/DegCelsius)
* V25 = temperature sensor @25degC and Vdda 3.3V (unit: mV)
* Calculation validity conditioned to settings:
* - ADC resolution 12 bits (need to scale value if using a different
* resolution).
* - Power supply of analog voltage Vdda 3.3V (need to scale value
* if using a different analog voltage supply value).
* @param TS_ADC_DATA: Temperature sensor digital value measured by ADC
* @retval None
*/
#define COMPUTATION_TEMPERATURE_STD_PARAMS(TS_ADC_DATA) \
((((int32_t)(INTERNAL_TEMPSENSOR_V25 - (((TS_ADC_DATA) * VDD_APPLI) / RANGE_12BITS) \
) * 1000 \
) / INTERNAL_TEMPSENSOR_AVGSLOPE \
) + 25 \
)
/**
* @brief Computation of voltage (unit: mV) from ADC measurement digital
* value on range 12 bits.
* Calculation validity conditioned to settings:
* - ADC resolution 12 bits (need to scale value if using a different
* resolution).
* - Power supply of analog voltage Vdda 3.3V (need to scale value
* if using a different analog voltage supply value).
* @param ADC_DATA: Digital value measured by ADC
* @retval None
*/
#define COMPUTATION_DIGITAL_12BITS_TO_VOLTAGE(ADC_DATA) \
( (ADC_DATA) * VDD_APPLI / RANGE_12BITS)
/* Private variables ---------------------------------------------------------*/
/* ADC handler declaration */
ADC_HandleTypeDef AdcHandle;
#if defined(WAVEFORM_VOLTAGE_GENERATION_FOR_TEST)
/* DAC handler declaration */
DAC_HandleTypeDef DacHandle;
#endif /* WAVEFORM_VOLTAGE_GENERATION_FOR_TEST */
/* Variable containing ADC conversions results */
__IO uint16_t aADCxConvertedValues[ADCCONVERTEDVALUES_BUFFER_SIZE];
/* Variables for ADC conversions results computation to physical values */
uint16_t uhADCChannelToDAC_mVolt = 0;
uint16_t uhVrefInt_mVolt = 0;
int32_t wTemperature_DegreeCelsius = 0;
/* Variables to manage push button on board: interface between ExtLine interruption and main program */
uint8_t ubUserButtonClickCount = 0; /* Count number of clicks: Incremented after User Button interrupt */
__IO uint8_t ubUserButtonClickEvent = RESET; /* Event detection: Set after User Button interrupt */
/* Variable to report ADC sequencer status */
uint8_t ubSequenceCompleted = RESET; /* Set when all ranks of the sequence have been converted */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void Error_Handler(void);
static void ADC_Config(void);
#if defined(WAVEFORM_VOLTAGE_GENERATION_FOR_TEST)
static void DAC_Config(void);
#endif /* WAVEFORM_VOLTAGE_GENERATION_FOR_TEST */
/* Private functions ---------------------------------------------------------*/
/**
* @brief Main program.
* @param None
* @retval None
*/
int main(void)
{
/* STM32F103xG HAL library initialization:
- Configure the Flash prefetch
- Systick timer is configured by default as source of time base, but user
can eventually implement his proper time base source (a general purpose
timer for example or other time source), keeping in mind that Time base
duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
handled in milliseconds basis.
- Set NVIC Group Priority to 4
- Low Level Initialization
*/
HAL_Init();
/* Configure the system clock to 72 MHz */
SystemClock_Config();
/*## Configure peripherals #################################################*/
/* Initialize LEDs on board */
BSP_LED_Init(LED3);
BSP_LED_Init(LED1);
/* Configure Key push-button in Interrupt mode */
BSP_PB_Init(BUTTON_KEY, BUTTON_MODE_EXTI);
/* Configure the ADC peripheral */
ADC_Config();
/* Run the ADC calibration */
if (HAL_ADCEx_Calibration_Start(&AdcHandle) != HAL_OK)
{
/* Calibration Error */
Error_Handler();
}
#if defined(WAVEFORM_VOLTAGE_GENERATION_FOR_TEST)
/* Configure the DAC peripheral */
DAC_Config();
#endif /* WAVEFORM_VOLTAGE_GENERATION_FOR_TEST */
/*## Enable peripherals ####################################################*/
#if defined(WAVEFORM_VOLTAGE_GENERATION_FOR_TEST)
/* Set DAC Channel data register: channel corresponding to ADC channel CHANNELa */
/* Set DAC output to 1/2 of full range (4095 <=> Vdda=3.3V): 2048 <=> 1.65V */
if (HAL_DAC_SetValue(&DacHandle, DACx_CHANNEL_TO_ADCx_CHANNELa, DAC_ALIGN_12B_R, RANGE_12BITS/2) != HAL_OK)
{
/* Setting value Error */
Error_Handler();
}
/* Enable DAC Channel: channel corresponding to ADC channel CHANNELa */
if (HAL_DAC_Start(&DacHandle, DACx_CHANNEL_TO_ADCx_CHANNELa) != HAL_OK)
{
/* Start Error */
Error_Handler();
}
#endif /* WAVEFORM_VOLTAGE_GENERATION_FOR_TEST */
/*## Start ADC conversions #################################################*/
/* Start ADC conversion on regular group with transfer by DMA */
if (HAL_ADC_Start_DMA(&AdcHandle,
(uint32_t *)aADCxConvertedValues,
ADCCONVERTEDVALUES_BUFFER_SIZE
) != HAL_OK)
{
/* Start Error */
Error_Handler();
}
/* Infinite loop */
while (1)
{
/* Wait for event on push button to perform following actions */
while ((ubUserButtonClickEvent) == RESET)
{
}
/* Reset variable for next loop iteration */
ubUserButtonClickEvent = RESET;
#if defined(WAVEFORM_VOLTAGE_GENERATION_FOR_TEST)
/* Set DAC voltage on channel corresponding to ADCx_CHANNELa */
/* in function of user button clicks count. */
/* Set DAC output successively to: */
/* - minimum of full range (0 <=> ground 0V) */
/* - 1/4 of full range (4095 <=> Vdda=3.3V): 1023 <=> 0.825V */
/* - 1/2 of full range (4095 <=> Vdda=3.3V): 2048 <=> 1.65V */
/* - 3/4 of full range (4095 <=> Vdda=3.3V): 3071 <=> 2.475V */
/* - maximum of full range (4095 <=> Vdda=3.3V) */
if (HAL_DAC_SetValue(&DacHandle,
DACx_CHANNEL_TO_ADCx_CHANNELa,
DAC_ALIGN_12B_R,
(RANGE_12BITS * ubUserButtonClickCount / USERBUTTON_CLICK_COUNT_MAX)
) != HAL_OK)
{
/* Start Error */
Error_Handler();
}
#endif /* WAVEFORM_VOLTAGE_GENERATION_FOR_TEST */
/* Wait for DAC settling time */
HAL_Delay(1);
/* Start ADC conversion */
/* Since sequencer is enabled in discontinuous mode, this will perform */
/* the conversion of the next rank in sequencer. */
/* Note: For this example, conversion is triggered by software start, */
/* therefore "HAL_ADC_Start()" must be called for each conversion. */
/* Since DMA transfer has been initiated previously by function */
/* "HAL_ADC_Start_DMA()", this function will keep DMA transfer */
/* active. */
HAL_ADC_Start(&AdcHandle);
/* Wait for conversion completion before conditional check hereafter */
HAL_ADC_PollForConversion(&AdcHandle, 1);
/* Turn-on/off LED1 in function of ADC sequencer status */
/* - Turn-off if sequencer has not yet converted all ranks */
/* - Turn-on if sequencer has converted all ranks */
if (ubSequenceCompleted == RESET)
{
BSP_LED_Off(LED1);
}
else
{
BSP_LED_On(LED1);
/* Computation of ADC conversions raw data to physical values */
/* Note: ADC results are transferred into array "aADCxConvertedValues" */
/* in the order of their rank in ADC sequencer. */
uhADCChannelToDAC_mVolt = COMPUTATION_DIGITAL_12BITS_TO_VOLTAGE(aADCxConvertedValues[0]);
uhVrefInt_mVolt = COMPUTATION_DIGITAL_12BITS_TO_VOLTAGE(aADCxConvertedValues[2]);
wTemperature_DegreeCelsius = COMPUTATION_TEMPERATURE_STD_PARAMS(aADCxConvertedValues[1]);
/* Reset variable for next loop iteration */
ubSequenceCompleted = RESET;
}
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 72000000
* HCLK(Hz) = 72000000
* AHB Prescaler = 1
* APB1 Prescaler = 2
* APB2 Prescaler = 1
* HSE Frequency(Hz) = 8000000
* HSE PREDIV1 = 1
* PLLMUL = 9
* Flash Latency(WS) = 2
* @param None
* @retval None
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef clkinitstruct = {0};
RCC_OscInitTypeDef oscinitstruct = {0};
/* Enable HSE Oscillator and activate PLL with HSE as source */
oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
oscinitstruct.HSEState = RCC_HSE_ON;
oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
oscinitstruct.PLL.PLLState = RCC_PLL_ON;
oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
{
/* Initialization Error */
while(1);
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
{
/* Initialization Error */
while(1);
}
}
/**
* @brief ADC configuration
* @param None
* @retval None
*/
static void ADC_Config(void)
{
ADC_ChannelConfTypeDef sConfig;
/* Configuration of ADCx init structure: ADC parameters and regular group */
AdcHandle.Instance = ADCx;
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
AdcHandle.Init.ScanConvMode = ADC_SCAN_ENABLE; /* Sequencer disabled (ADC conversion on only 1 channel: channel set on rank 1) */
AdcHandle.Init.ContinuousConvMode = DISABLE; /* Continuous mode disabled to have only 1 rank converted at each conversion trig, and because discontinuous mode is enabled */
AdcHandle.Init.NbrOfConversion = 3; /* Sequencer of regular group will convert the 3 first ranks: rank1, rank2, rank3 */
AdcHandle.Init.DiscontinuousConvMode = ENABLE; /* Sequencer of regular group will convert the sequence in several sub-divided sequences */
AdcHandle.Init.NbrOfDiscConversion = 1; /* Sequencer of regular group will convert ranks one by one, at each conversion trig */
AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* Trig of conversion start done manually by software, without external event */
if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
{
/* ADC initialization error */
Error_Handler();
}
/* Configuration of channel on ADCx regular group on sequencer rank 1 */
/* Note: Considering IT occurring after each ADC conversion (IT by DMA end */
/* of transfer), select sampling time and ADC clock with sufficient */
/* duration to not create an overhead situation in IRQHandler. */
/* Note: Set long sampling time due to internal channels (VrefInt, */
/* temperature sensor) constraints. Refer to device datasheet for */
/* min/typ/max values. */
sConfig.Channel = ADCx_CHANNELa;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
Error_Handler();
}
/* Configuration of channel on ADCx regular group on sequencer rank 2 */
/* Replicate previous rank settings, change only channel and rank */
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_REGULAR_RANK_2;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
Error_Handler();
}
/* Configuration of channel on ADCx regular group on sequencer rank 3 */
/* Replicate previous rank settings, change only channel and rank */
sConfig.Channel = ADC_CHANNEL_VREFINT;
sConfig.Rank = ADC_REGULAR_RANK_3;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
/* Channel Configuration Error */
Error_Handler();
}
}
#if defined(WAVEFORM_VOLTAGE_GENERATION_FOR_TEST)
/**
* @brief DAC configuration
* @param None
* @retval None
*/
static void DAC_Config(void)
{
static DAC_ChannelConfTypeDef sConfig;
/* Configuration of DACx peripheral */
DacHandle.Instance = DACx;
if (HAL_DAC_Init(&DacHandle) != HAL_OK)
{
/* DAC initialization error */
Error_Handler();
}
/* Configuration of DAC channel */
sConfig.DAC_Trigger = DAC_TRIGGER_NONE;
sConfig.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
if (HAL_DAC_ConfigChannel(&DacHandle, &sConfig, DACx_CHANNEL_TO_ADCx_CHANNELa) != HAL_OK)
{
/* Channel configuration error */
Error_Handler();
}
}
#endif /* WAVEFORM_VOLTAGE_GENERATION_FOR_TEST */
/**
* @brief EXTI line detection callbacks
* @param GPIO_Pin: Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == KEY_BUTTON_PIN)
{
/* Set variable to report push button event to main program */
ubUserButtonClickEvent = SET;
/* Manage ubUserButtonClickCount to increment it circularly from 0 to */
/* maximum value defined */
if (ubUserButtonClickCount < USERBUTTON_CLICK_COUNT_MAX)
{
ubUserButtonClickCount++;
}
else
{
ubUserButtonClickCount=0;
}
}
}
/**
* @brief Conversion complete callback in non blocking mode
* @param AdcHandle : AdcHandle handle
* @note This example shows a simple way to report end of conversion
* and get conversion result. You can add your own implementation.
* @retval None
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *AdcHandle)
{
/* Report to main program that ADC sequencer has reached its end */
ubSequenceCompleted = SET;
}
/**
* @brief Conversion DMA half-transfer callback in non blocking mode
* @param hadc: ADC handle
* @retval None
*/
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
{
}
/**
* @brief ADC error callback in non blocking mode
* (ADC conversion with interruption or transfer by DMA)
* @param hadc: ADC handle
* @retval None
*/
void HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc)
{
/* In case of ADC error, call main error handler */
Error_Handler();
}
/**
* @brief This function is executed in case of error occurrence.
* @param None
* @retval None
*/
static void Error_Handler(void)
{
/* User may add here some code to deal with a potential error */
/* In case of error, LED3 is toggling at a frequency of 1Hz */
while(1)
{
/* Toggle LED3 */
BSP_LED_Toggle(LED3);
HAL_Delay(500);
}
}
#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\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/