DIY Logging Volt/Ampmeter
adc.c
Go to the documentation of this file.
1 /**
2  ******************************************************************************
3  * @file adc.c
4  * @brief This file provides code for the configuration
5  * of the ADC instances.
6  ******************************************************************************
7  * @attention
8  *
9  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
10  * All rights reserved.</center></h2>
11  *
12  * This software component is licensed by ST under BSD 3-Clause license,
13  * the "License"; You may not use this file except in compliance with the
14  * License. You may obtain a copy of the License at:
15  * opensource.org/licenses/BSD-3-Clause
16  *
17  ******************************************************************************
18  */
19 
20 /* Includes ------------------------------------------------------------------*/
21 #include "adc.h"
22 
23 /* USER CODE BEGIN 0 */
24 
25 // TODO Got example from https://github.com/STMicroelectronics/STM32CubeF1/tree/master/Projects/STM32F103RB-Nucleo/Examples_LL/ADC/ADC_SingleConversion_TriggerSW_IT
26 
27 #include "SEGGER_RTT.h"
28 #include "util.h"
29 #include "conversion.h"
30 
31 
32 /* Private typedef -----------------------------------------------------------*/
33 /* Private define ------------------------------------------------------------*/
34 
35 /* Definitions of ADC hardware constraints delays */
36 /* Note: Only ADC IP HW delays are defined in ADC LL driver driver, */
37 /* not timeout values: */
38 /* Timeout values for ADC operations are dependent to device clock */
39 /* configuration (system clock versus ADC clock), */
40 /* and therefore must be defined in user application. */
41 /* Refer to @ref ADC_LL_EC_HW_DELAYS for description of ADC timeout */
42 /* values definition. */
43 
44  /* Timeout values for ADC operations. */
45  /* (enable settling time, disable settling time, ...) */
46  /* Values defined to be higher than worst cases: low clock frequency, */
47  /* maximum prescalers. */
48  /* Example of profile very low frequency : ADC clock frequency 12MHz */
49  /* prescaler 6, sampling time 1.5 ADC clock cycles, resolution 12 bits. */
50  /* - ADC enable time: maximum delay is 1 us */
51  /* (refer to device datasheet, parameter "tSTAB") */
52  /* - ADC disable time: maximum delay should be a few ADC clock cycles */
53  /* - ADC stop conversion time: maximum delay should be a few ADC clock */
54  /* cycles */
55  /* - ADC conversion time: with this hypothesis of clock settings, maximum */
56  /* delay will be 7us. */
57  /* (refer to device reference manual, section "Timing") */
58  /* Unit: ms */
59  #define ADC_CALIBRATION_TIMEOUT_MS ((uint32_t) 1)
60  #define ADC_ENABLE_TIMEOUT_MS ((uint32_t) 1)
61  #define ADC_DISABLE_TIMEOUT_MS ((uint32_t) 1)
62  #define ADC_STOP_CONVERSION_TIMEOUT_MS ((uint32_t) 1)
63  #define ADC_CONVERSION_TIMEOUT_MS ((uint32_t) 2)
64 
65  /* Delay between ADC enable and ADC end of calibration. */
66  /* Delay estimation in CPU cycles: Case of ADC calibration done */
67  /* immediately after ADC enable, ADC clock setting slow */
68  /* (LL_ADC_CLOCK_ASYNC_DIV32). Use a higher delay if ratio */
69  /* (CPU clock / ADC clock) is above 32. */
70  #define ADC_DELAY_ENABLE_CALIB_CPU_CYCLES (LL_ADC_DELAY_ENABLE_CALIB_ADC_CYCLES * 32)
71 
72 
73 /* Definitions of environment analog values */
74  /* Value of analog reference voltage (Vref+), connected to analog voltage */
75  /* supply Vdda (unit: mV). */
76  #define VDDA_APPLI ((uint32_t)3300)
77 
78 /* Definitions of data related to this example */
79  /* Init variable out of expected ADC conversion data range */
80  #define VAR_CONVERTED_DATA_INIT_VALUE (__LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_12B) + 1)
81 
82 /* Private macro -------------------------------------------------------------*/
83 /* Private variables ---------------------------------------------------------*/
84 
85 /* Value to add to the converted ADC voltage as a sort of calibration */
86 static const float adcVoltReadoutCalbration = 0.03;
87 
88 /* Variables for ADC conversion data */
89 __IO uint16_t uhADCxConvertedData = VAR_CONVERTED_DATA_INIT_VALUE; /* ADC group regular conversion data */
90 
91 /* Variables for ADC conversion data computation to physical values */
92 __IO uint16_t uhADCxConvertedData_Voltage_mVolt = 0; /* Value of voltage calculated from ADC conversion data (unit: mV) */
93 
94 /* Variable to report status of ADC group regular unitary conversion */
95 /* 0: ADC group regular unitary conversion is not completed */
96 /* 1: ADC group regular unitary conversion is completed */
97 /* 2: ADC group regular unitary conversion has not been started yet */
98 /* (initial state) */
99 __IO uint8_t ubAdcGrpRegularUnitaryConvStatus = 2; /* Variable set into ADC interruption callback */
100 
101 
102 /* USER CODE END 0 */
103 
104 /* ADC1 init function */
105 void MX_ADC1_Init(void)
106 {
107  LL_ADC_InitTypeDef ADC_InitStruct = {0};
108  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
109  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
110 
111  /* Peripheral clock enable */
112  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
113 
114  /* ADC1 interrupt Init */
117 
118  /** Common config
119  */
120  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
121  ADC_InitStruct.SequencersScanMode = LL_ADC_SEQ_SCAN_DISABLE;
122  LL_ADC_Init(ADC1, &ADC_InitStruct);
123  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
124  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
125  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
126  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
127  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
128  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
129  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
130  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
131  /** Configure Regular Channel
132  */
133  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_TEMPSENSOR);
134  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_TEMPSENSOR, LL_ADC_SAMPLINGTIME_1CYCLE_5);
135  LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(ADC1), LL_ADC_PATH_INTERNAL_TEMPSENSOR);
136 }
137 
138 
139 /* ADC2 init function */
140 void MX_ADC2_Init(void)
141 {
142  LL_ADC_InitTypeDef ADC_InitStruct = {0};
143  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
144 
145  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
146 
147  /* Peripheral clock enable */
148  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC2);
149 
150  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
151  /**ADC2 GPIO Configuration
152  PB0 ------> ADC2_IN8
153  */
154  GPIO_InitStruct.Pin = LL_GPIO_PIN_0;
155  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
156  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
157 
158  /* ADC2 interrupt Init */
161 
162  /** Common config
163  */
164  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
165  ADC_InitStruct.SequencersScanMode = LL_ADC_SEQ_SCAN_DISABLE;
166  LL_ADC_Init(ADC2, &ADC_InitStruct);
167  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_SOFTWARE;
168  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
169  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
170  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
171  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_NONE;
172  LL_ADC_REG_Init(ADC2, &ADC_REG_InitStruct);
173  /** Configure Regular Channel
174  */
175  LL_ADC_REG_SetSequencerRanks(ADC2, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_8);
176  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_8, LL_ADC_SAMPLINGTIME_1CYCLE_5);
177 }
178 
179 /* USER CODE BEGIN 1 */
180 
181 /**
182  * @brief Perform ADC activation procedure to make it ready to convert
183  * (ADC instance: ADC2).
184  * @note Operations:
185  * - ADC instance
186  * - Run ADC self calibration
187  * - Enable ADC
188  * - ADC group regular
189  * none: ADC conversion start-stop to be performed
190  * after this function
191  * - ADC group injected
192  * none: ADC conversion start-stop to be performed
193  * after this function
194  * @param None
195  * @retval None
196  */
197 void Activate_ADC(void)
198 {
199  /* Increase sampling time */
200  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_8, LL_ADC_SAMPLINGTIME_28CYCLES_5);
201 
202  /* Enable interruption ADC group regular end of unitary conversion */
203  LL_ADC_EnableIT_EOS(ADC2);
204 
205 
206  /* Logic discribe in the note now follows */
207  __IO uint32_t wait_loop_index = 0;
208 
209  uint32_t Timeout = 0; /* Variable used for timeout management */
210 
211  /*## Operation on ADC hierarchical scope: ADC instance #####################*/
212 
213  /* Note: Hardware constraint (refer to description of the functions */
214  /* below): */
215  /* On this STM32 serie, setting of these features are not */
216  /* conditioned to ADC state. */
217  /* However, in order to be compliant with other STM32 series */
218  /* and to show the best practice usages, ADC state is checked. */
219  /* Software can be optimized by removing some of these checks, if */
220  /* they are not relevant considering previous settings and actions */
221  /* in user application. */
222  if (LL_ADC_IsEnabled(ADC2) == 0)
223  {
224  /* Enable ADC */
225  LL_ADC_Enable(ADC2);
226 
227  /* Delay between ADC enable and ADC start of calibration. */
228  /* Note: Variable divided by 2 to compensate partially */
229  /* CPU processing cycles (depends on compilation optimization). */
230  wait_loop_index = (ADC_DELAY_ENABLE_CALIB_CPU_CYCLES >> 1);
231  while (wait_loop_index != 0) wait_loop_index--;
232 
233  /* Run ADC self calibration */
234  LL_ADC_StartCalibration(ADC2);
235 
236  /* Poll for ADC effectively calibrated */
238 
239  while (LL_ADC_IsCalibrationOnGoing(ADC2) != 0)
240  {
241  /* Check Systick counter flag to decrement the time-out value */
243  {
244  if (Timeout-- == 0) while (1); /* Time-out occurred */
245  }
246  }
247  }
248 
249  /*## Operation on ADC hierarchical scope: ADC group regular ################*/
250  /* Note: No operation on ADC group regular performed here. */
251  /* ADC group regular conversions to be performed after this function */
252  /* using function: */
253  /* "LL_ADC_REG_StartConversion();" */
254 
255  /*## Operation on ADC hierarchical scope: ADC group injected ###############*/
256  /* Note: No operation on ADC group injected performed here. */
257  /* ADC group injected conversions to be performed after this function */
258  /* using function: */
259  /* "LL_ADC_INJ_StartConversion();" */
260 
261 }
262 
263 
265 {
266  /* Reset status variable of ADC group regular unitary conversion before */
267  /* performing a new ADC group regular conversion start. */
268  /* Note: Optionally, for this example purpose, check ADC unitary */
269  /* conversion status before starting another ADC conversion. */
270 
272  {
274  }
275  else
276  {
277  /* Error: Previous action (ADC conversion or DMA transfer) not yet */
278  /* completed. */
279  while (1);
280  }
281 
282  /* Init variable containing ADC conversion data */
284 
285  /* Start ADC group regular conversion */
286  /* Note: Hardware constraint (refer to description of the functions */
287  /* below): */
288  /* On this STM32 serie, setting of these features are not */
289  /* conditioned to ADC state. */
290  /* However, in order to be compliant with other STM32 series */
291  /* and to show the best practice usages, ADC state is checked. */
292  /* Software can be optimized by removing some of these checks, if */
293  /* they are not relevant considering previous settings and actions */
294  /* in user application. */
295  if (LL_ADC_IsEnabled(ADC2) == 1) LL_ADC_REG_StartConversionSWStart(ADC2);
296  else
297  {
298  /* Error: ADC conversion start could not be performed */
299  while(1);
300  }
301 
302 }
303 
304 
305 /**
306  * @brief ADC group regular end of unitary conversion interruption callback
307  * @note This function is executed when the ADC group regular
308  * sequencer has converted one rank of the sequence.
309  * Therefore, this function is executed as many times as number
310  * of ranks in the sequence.
311  * @retval None
312  */
314 {
315  /* Retrieve ADC conversion data */
316  /* (data maximum amplitude corresponds to ADC resolution: 12 bits) */
317  uhADCxConvertedData = LL_ADC_REG_ReadConversionData12(ADC2);
318 
319  /* Computation of ADC conversions raw data to physical values */
320  /* using LL ADC driver helper macro. */
321  uhADCxConvertedData_Voltage_mVolt = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData, LL_ADC_RESOLUTION_12B);
322 
323  /* Update status variable of ADC unitary conversion */
325 
326  /* Calculate real voltage */
327  settings.vbat = ((uhADCxConvertedData_Voltage_mVolt * 0.001) * 3.2) / 2.2; /* Voltage divider of 1kohm and 2.2kohm */
328 
329  /* Read voltage tends to be 0.03V lower so add this value manually (~calibration) */
331 
332 // SEGGER_RTT_printf(0, "ADC = %u mV vbat = %u mV\n\r", uhADCxConvertedData_Voltage_mVolt, (uint16_t)(settings.vbat * 1000));
333 
334  /* Signal logic that the battery voltage needs to be converted */
335  settings.newVbat = 1;
336 }
337 
338 /* USER CODE END 1 */
339 
340 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
ADC_CALIBRATION_TIMEOUT_MS
#define ADC_CALIBRATION_TIMEOUT_MS
Definition: adc.c:59
ubAdcGrpRegularUnitaryConvStatus
__IO uint8_t ubAdcGrpRegularUnitaryConvStatus
Definition: adc.c:99
Timeout
static uint32_t Timeout
Definition: rtc.c:85
settings
struct Settings_t settings
NVIC_GetPriorityGrouping
#define NVIC_GetPriorityGrouping
Definition: core_armv8mbl.h:1189
uhADCxConvertedData_Voltage_mVolt
__IO uint16_t uhADCxConvertedData_Voltage_mVolt
Definition: adc.c:92
ADC_DELAY_ENABLE_CALIB_CPU_CYCLES
#define ADC_DELAY_ENABLE_CALIB_CPU_CYCLES
Definition: adc.c:70
startBattVoltMeasurement
void startBattVoltMeasurement(void)
Definition: adc.c:264
uhADCxConvertedData
__IO uint16_t uhADCxConvertedData
Definition: adc.c:89
LL_SYSTICK_IsActiveCounterFlag
__STATIC_INLINE uint32_t LL_SYSTICK_IsActiveCounterFlag(void)
This function checks if the Systick counter flag is active or not.
Definition: stm32f1xx_ll_cortex.h:231
NVIC_EncodePriority
__STATIC_INLINE uint32_t NVIC_EncodePriority(uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority)
Encode Priority.
Definition: core_armv8mbl.h:1496
adc.h
This file contains all the function prototypes for the adc.c file.
VAR_CONVERTED_DATA_INIT_VALUE
#define VAR_CONVERTED_DATA_INIT_VALUE
Definition: adc.c:80
ADC1_2_IRQn
@ ADC1_2_IRQn
Definition: stm32f103xb.h:101
adcVoltReadoutCalbration
static const float adcVoltReadoutCalbration
Definition: adc.c:86
ADC1
#define ADC1
Definition: stm32f103xb.h:670
Activate_ADC
void Activate_ADC(void)
Perform ADC activation procedure to make it ready to convert (ADC instance: ADC2).
Definition: adc.c:197
conversion.h
Conversion and settings-related methods and structs for high-precision logging voltage/current meter.
GPIOB
#define GPIOB
Definition: stm32f103xb.h:666
__IO
#define __IO
Definition: core_armv8mbl.h:196
MX_ADC2_Init
void MX_ADC2_Init(void)
Definition: adc.c:140
NVIC_SetPriority
#define NVIC_SetPriority
Definition: core_armv8mbl.h:1197
AdcGrpRegularUnitaryConvComplete_Callback
void AdcGrpRegularUnitaryConvComplete_Callback(void)
ADC group regular end of unitary conversion interruption callback.
Definition: adc.c:313
NVIC_EnableIRQ
#define NVIC_EnableIRQ
Definition: core_armv8mbl.h:1190
MX_ADC1_Init
void MX_ADC1_Init(void)
Definition: adc.c:105
ADC2
#define ADC2
Definition: stm32f103xb.h:671
SEGGER_RTT.h
Settings_t::vbat
volatile float vbat
Definition: conversion.h:139
Settings_t::newVbat
volatile uint8_t newVbat
Definition: conversion.h:140
util.h
Utility functionality for high-precision logging voltage/current meter.
VDDA_APPLI
#define VDDA_APPLI
Definition: adc.c:76