px-fwlib 0.10.0
Cross-platform embedded library and documentation for 8/16/32-bit microcontrollers generated with Doxygen 1.9.2
px_adc.c
1/* =============================================================================
2 ____ ___ ____ ___ _ _ ___ __ __ ___ __ __ TM
3 | _ \ |_ _| / ___| / _ \ | \ | | / _ \ | \/ | |_ _| \ \/ /
4 | |_) | | | | | | | | | | \| | | | | | | |\/| | | | \ /
5 | __/ | | | |___ | |_| | | |\ | | |_| | | | | | | | / \
6 |_| |___| \____| \___/ |_| \_| \___/ |_| |_| |___| /_/\_\
7
8 Copyright (c) 2018 Pieter Conradie <https://piconomix.com>
9
10 License: MIT
11 https://github.com/piconomix/px-fwlib/blob/master/LICENSE.md
12
13 Title: px_adc.h : ADC peripheral driver
14 Author(s): Pieter Conradie
15 Creation Date: 2018-11-04
16
17============================================================================= */
18
19/* _____STANDARD INCLUDES____________________________________________________ */
20
21/* _____PROJECT INCLUDES_____________________________________________________ */
22#include "px_adc.h"
23#include "px_board.h"
24#include "px_stm32cube.h"
25#include "px_log.h"
26
27/* _____LOCAL DEFINITIONS____________________________________________________ */
28PX_LOG_NAME("px_adc");
29
30/// Internal data for each ADC handle
31typedef struct px_adc_per_s
32{
33 ADC_TypeDef * adc_base_adr; ///< ADC peripheral base register address
34 px_adc_nr_t adc_nr; ///< ADC peripheral number
35 uint8_t open_counter; ///< Number of open handles referencing peripheral
37
38/* _____MACROS_______________________________________________________________ */
39
40/* _____GLOBAL VARIABLES_____________________________________________________ */
41
42/* _____LOCAL VARIABLES______________________________________________________ */
43/// Allocate data for each enabled ADC peripheral
44#if PX_ADC_CFG_ADC1_EN
45static px_adc_per_t px_adc_per_1;
46#endif
47
48/* _____LOCAL FUNCTION DECLARATIONS__________________________________________ */
49
50/* _____LOCAL FUNCTIONS______________________________________________________ */
51static void px_adc_init_per(ADC_TypeDef * adc_base_adr,
52 px_adc_nr_t adc_nr)
53{
54 // Enable peripheral clock
55 switch(adc_nr)
56 {
57#if PX_ADC_CFG_ADC1_EN
58 case PX_ADC_NR_1:
59 LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_ADC1);
60 break;
61#endif
62 default:
63 PX_LOG_E("Invalid peripheral");
64 return;
65 }
66 // Set ADC clock source
67 switch(PX_ADC_CFG_CLK)
68 {
70 LL_ADC_SetClock(adc_base_adr, LL_ADC_CLOCK_SYNC_PCLK_DIV1);
71 break;
73 LL_ADC_SetClock(adc_base_adr, LL_ADC_CLOCK_SYNC_PCLK_DIV2);
74 break;
76 LL_ADC_SetClock(adc_base_adr, LL_ADC_CLOCK_SYNC_PCLK_DIV4);
77 break;
78 default:
79 PX_LOG_E("Unsupported ADC clock");
80 break;
81 }
82 // Enable regulator
83 LL_ADC_EnableInternalRegulator(adc_base_adr);
84 // Set ADC sampling time
85 LL_ADC_SetSamplingTimeCommonChannels(adc_base_adr, PX_ADC_CFG_SAMPLE_TIME);
86 // Set ADC resolution
87 LL_ADC_SetResolution(adc_base_adr, PX_ADC_CFG_RES_12_BITS << ADC_CFGR1_RES_Pos);
88 // Set ADC oversampling and shift
90 {
91 LL_ADC_SetOverSamplingScope(adc_base_adr, LL_ADC_OVS_GRP_REGULAR_CONTINUED);
92 LL_ADC_ConfigOverSamplingRatioShift(adc_base_adr,
93 ((uint32_t)PX_ADC_CFG_OVERSAMPLING - 1 ) << ADC_CFGR2_OVSR_Pos,
94 ((uint32_t)PX_ADC_CFG_OVERSAMPLING_SHIFT) << ADC_CFGR2_OVSS_Pos);
95 }
96 // Calibrate ADC
97 LL_ADC_StartCalibration(adc_base_adr);
98 while(LL_ADC_IsCalibrationOnGoing(adc_base_adr)) {;}
99 // Enable peripheral
100 LL_ADC_ClearFlag_ADRDY(adc_base_adr);
101 LL_ADC_Enable(adc_base_adr);
102 while(LL_ADC_IsActiveFlag_ADRDY(adc_base_adr) == 0) {;}
103}
104
105
106static void px_adc_init_per_data(px_adc_nr_t adc_nr,
107 px_adc_per_t * adc_per)
108{
109 // Set peripheral number
110 adc_per->adc_nr = adc_nr;
111 // Set peripheral base address
112 switch(adc_nr)
113 {
114#if PX_ADC_CFG_ADC1_EN
115 case PX_ADC_NR_1:
116 adc_per->adc_base_adr = ADC1;
117 break;
118#endif
119 default:
120 PX_LOG_E("Invalid peripheral");
121 return;
122 }
123 // Clear reference counter
124 adc_per->open_counter = 0;
125}
126
127/* _____GLOBAL FUNCTIONS_____________________________________________________ */
128void px_adc_init(void)
129{
130 // Initialize peripheral data for each enabled peripheral
131#if PX_ADC_CFG_ADC1_EN
132 px_adc_init_per_data(PX_ADC_NR_1, &px_adc_per_1);
133#endif
134}
135
137 px_adc_nr_t adc_nr)
138{
139 px_adc_per_t * adc_per;
140
141#if PX_LOG
142 // Verify that pointer to handle is not NULL
143 if(handle == NULL)
144 {
145 PX_LOG_ASSERT(false);
146 return false;
147 }
148#endif
149
150 // Handle not initialised
151 handle->adc_per = NULL;
152 // Set pointer to peripheral data
153 switch(adc_nr)
154 {
155#if PX_ADC_CFG_ADC1_EN
156 case PX_ADC_NR_1:
157 adc_per = &px_adc_per_1;
158 break;
159#endif
160 default:
161 PX_LOG_E("Invalid peripheral specified");
162 return false;
163 }
164#if PX_LOG
165 // Check that px_adc_init() has been called
166 if(adc_per->adc_base_adr == NULL)
167 {
168 PX_LOG_ASSERT(false);
169 return false;
170 }
171#endif
172 // Initialise peripheral
173 px_adc_init_per(adc_per->adc_base_adr, adc_nr);
174 // Point handle to peripheral
175 handle->adc_per = adc_per;
176 // Success
177 adc_per->open_counter++;
178 return true;
179}
180
182{
183 px_adc_per_t * adc_per;
184 ADC_TypeDef * adc_base_adr;
185
186#if PX_LOG
187 // Check handle
188 if( (handle == NULL)
189 ||(handle->adc_per == NULL)
190 ||(handle->adc_per->adc_base_adr == NULL)
191 ||(handle->adc_per->open_counter == 0 ) )
192 {
193 PX_LOG_ASSERT(false);
194 return false;
195 }
196#endif
197
198 // Set pointer to peripheral
199 adc_per = handle->adc_per;
200 // Get ADC peripheral base register address
201 adc_base_adr = adc_per->adc_base_adr;
202 // Decrement open count
203 adc_per->open_counter--;
204 // More open handles referencing peripheral?
205 if(adc_per->open_counter != 0)
206 {
207 // Close handle
208 handle->adc_per = NULL;
209 // Success
210 return true;
211 }
212 // Disable peripheral
213 LL_ADC_Disable(adc_base_adr);
214 while(LL_ADC_IsDisableOngoing(adc_base_adr)) {;}
215 // Disable regulator
216 LL_ADC_DisableInternalRegulator(adc_base_adr);
217 while(LL_ADC_IsInternalRegulatorEnabled(adc_base_adr)) {;}
218 // Disable peripheral clock
219 switch(handle->adc_per->adc_nr)
220 {
221#if PX_ADC_CFG_ADC1_EN
222 case PX_ADC_NR_1:
223 LL_APB2_GRP1_DisableClock(LL_APB2_GRP1_PERIPH_ADC1);
224 break;
225#endif
226 default:
227 break;
228 }
229 // Close handle
230 handle->adc_per = NULL;
231 // Success
232 return true;
233}
234
236{
237 px_adc_per_t * adc_per;
238 ADC_TypeDef * adc_base_adr;
239 uint16_t data;
240
241#if PX_LOG
242 // Check handle
243 if( (handle == NULL)
244 ||(handle->adc_per == NULL)
245 ||(handle->adc_per->adc_base_adr == NULL)
246 ||(handle->adc_per->open_counter == 0 ) )
247 {
248 PX_LOG_ASSERT(false);
249 return false;
250 }
251#endif
252
253 // Set pointer to peripheral
254 adc_per = handle->adc_per;
255 // Get ADC peripheral base register address
256 adc_base_adr = adc_per->adc_base_adr;
257 // Select channel
258 adc_base_adr->CHSELR = PX_ADC_CH_TO_BITMASK(ch);
259 // Start conversion
260 LL_ADC_REG_StartConversion(adc_base_adr);
261 // Wait for conversion to finish
262 while(LL_ADC_REG_IsConversionOngoing(adc_base_adr)) {;}
263 // Read result
264 data = LL_ADC_REG_ReadConversionData12(adc_base_adr);
265
266 return data;
267}
#define NULL
NULL pointer.
Definition: px_defs.h:49
#define PX_LOG_NAME(name)
Macro to declare a log name string once for each file to reduce code size.
Definition: px_log.h:349
#define PX_LOG_E(format,...)
Macro to display a formatted ERROR message.
Definition: px_log.h:377
#define PX_LOG_ASSERT(expression)
Macro that will test an expression, and block indefinitely if false.
Definition: px_log.h:440
struct px_adc_per_s * adc_per
ADC peripheral data.
Definition: px_adc.h:164
#define PX_ADC_CFG_OVERSAMPLING_SHIFT
Specify ADC oversampling (see 'px_adc_cfg_oversampling_shift_t')
#define PX_ADC_CFG_CLK
Specify ADC clock source (see 'px_adc_cfg_clk_t')
void px_adc_init(void)
Initialise ADC driver.
Definition: px_adc.c:128
px_adc_nr_t
Specify ADC peripheral.
Definition: px_adc.h:75
px_adc_ch_t
Specify ADC channel.
Definition: px_adc.h:81
#define PX_ADC_CFG_OVERSAMPLING
Specify ADC oversampling (see 'px_adc_cfg_oversampling_t')
bool px_adc_close(px_adc_handle_t *handle)
Close specified device.
Definition: px_adc.c:181
bool px_adc_open(px_adc_handle_t *handle, px_adc_nr_t adc_nr)
Open ADC peripheral using predefined (default) parameters.
Definition: px_adc.c:136
#define PX_ADC_CFG_SAMPLE_TIME
Specify ADC sampling time (see 'px_adc_cfg_sample_time_t')
uint16_t px_adc_sample(px_adc_handle_t *handle, px_adc_ch_t ch)
Perform a single measurement on the specified ADC channel.
Definition: px_adc.c:235
#define PX_ADC_CH_TO_BITMASK(ch)
Convert ADC channel number into bit mask.
Definition: px_adc.h:212
@ PX_ADC_CFG_OVERSAMPLING_NONE
No oversampling.
Definition: px_adc.h:136
@ PX_ADC_CFG_RES_12_BITS
12-bit resolution
Definition: px_adc.h:127
@ PX_ADC_CFG_CLK_PCLK_DIV2
Peripheral Clock / 2.
Definition: px_adc.h:107
@ PX_ADC_CFG_CLK_PCLK
Peripheral Clock.
Definition: px_adc.h:106
@ PX_ADC_CFG_CLK_PCLK_DIV4
Peripheral Clock / 4.
Definition: px_adc.h:108
Define ADC handle.
Definition: px_adc.h:163
Internal data for each ADC handle.
Definition: px_adc.c:32
ADC_TypeDef * adc_base_adr
ADC peripheral base register address.
Definition: px_adc.c:33
uint8_t open_counter
Number of open handles referencing peripheral.
Definition: px_adc.c:35
px_adc_nr_t adc_nr
ADC peripheral number.
Definition: px_adc.c:34