aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios/os/hal/ports/STM32/STM32F1xx/hal_adc_lld.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios/os/hal/ports/STM32/STM32F1xx/hal_adc_lld.c')
-rw-r--r--lib/chibios/os/hal/ports/STM32/STM32F1xx/hal_adc_lld.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/lib/chibios/os/hal/ports/STM32/STM32F1xx/hal_adc_lld.c b/lib/chibios/os/hal/ports/STM32/STM32F1xx/hal_adc_lld.c
new file mode 100644
index 000000000..ac44ea553
--- /dev/null
+++ b/lib/chibios/os/hal/ports/STM32/STM32F1xx/hal_adc_lld.c
@@ -0,0 +1,235 @@
1/*
2 ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17/**
18 * @file STM32F1xx/hal_adc_lld.c
19 * @brief STM32F1xx ADC subsystem low level driver source.
20 *
21 * @addtogroup ADC
22 * @{
23 */
24
25#include "hal.h"
26
27#if HAL_USE_ADC || defined(__DOXYGEN__)
28
29/*===========================================================================*/
30/* Driver local definitions. */
31/*===========================================================================*/
32
33/*===========================================================================*/
34/* Driver exported variables. */
35/*===========================================================================*/
36
37/** @brief ADC1 driver identifier.*/
38#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__)
39ADCDriver ADCD1;
40#endif
41
42/*===========================================================================*/
43/* Driver local variables and types. */
44/*===========================================================================*/
45
46/*===========================================================================*/
47/* Driver local functions. */
48/*===========================================================================*/
49
50/**
51 * @brief Shared ADC DMA ISR service routine.
52 *
53 * @param[in] adcp pointer to the @p ADCDriver object
54 * @param[in] flags pre-shifted content of the ISR register
55 */
56static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) {
57
58 /* DMA errors handling.*/
59 if ((flags & STM32_DMA_ISR_TEIF) != 0) {
60 /* DMA, this could help only if the DMA tries to access an unmapped
61 address space or violates alignment rules.*/
62 _adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE);
63 }
64 else {
65 if ((flags & STM32_DMA_ISR_TCIF) != 0) {
66 /* Transfer complete processing.*/
67 _adc_isr_full_code(adcp);
68 }
69 else if ((flags & STM32_DMA_ISR_HTIF) != 0) {
70 /* Half transfer processing.*/
71 _adc_isr_half_code(adcp);
72 }
73 }
74}
75
76/*===========================================================================*/
77/* Driver interrupt handlers. */
78/*===========================================================================*/
79
80/*===========================================================================*/
81/* Driver exported functions. */
82/*===========================================================================*/
83
84/**
85 * @brief Low level ADC driver initialization.
86 *
87 * @notapi
88 */
89void adc_lld_init(void) {
90
91#if STM32_ADC_USE_ADC1
92 /* Driver initialization.*/
93 adcObjectInit(&ADCD1);
94 ADCD1.adc = ADC1;
95 ADCD1.dmastp = NULL;
96 ADCD1.dmamode = STM32_DMA_CR_PL(STM32_ADC_ADC1_DMA_PRIORITY) |
97 STM32_DMA_CR_MSIZE_HWORD | STM32_DMA_CR_PSIZE_HWORD |
98 STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE |
99 STM32_DMA_CR_TEIE;
100
101 /* Temporary activation.*/
102 rccEnableADC1(true);
103 ADC1->CR1 = 0;
104 ADC1->CR2 = ADC_CR2_ADON;
105
106 /* Reset calibration just to be safe.*/
107 ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
108 while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
109 ;
110
111 /* Calibration.*/
112 ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
113 while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
114 ;
115
116 /* Return the ADC in low power mode.*/
117 ADC1->CR2 = 0;
118 rccDisableADC1();
119#endif
120}
121
122/**
123 * @brief Configures and activates the ADC peripheral.
124 *
125 * @param[in] adcp pointer to the @p ADCDriver object
126 *
127 * @notapi
128 */
129void adc_lld_start(ADCDriver *adcp) {
130
131 /* If in stopped state then enables the ADC and DMA clocks.*/
132 if (adcp->state == ADC_STOP) {
133#if STM32_ADC_USE_ADC1
134 if (&ADCD1 == adcp) {
135 adcp->dmastp = dmaStreamAllocI(STM32_DMA_STREAM_ID(1, 1),
136 STM32_ADC_ADC1_IRQ_PRIORITY,
137 (stm32_dmaisr_t)adc_lld_serve_rx_interrupt,
138 (void *)adcp);
139 osalDbgAssert(adcp->dmastp != NULL, "unable to allocate stream");
140 dmaStreamSetPeripheral(adcp->dmastp, &ADC1->DR);
141 rccEnableADC1(true);
142 }
143#endif
144
145 /* ADC setup, the calibration procedure has already been performed
146 during initialization.*/
147 adcp->adc->CR1 = 0;
148 adcp->adc->CR2 = 0;
149 }
150}
151
152/**
153 * @brief Deactivates the ADC peripheral.
154 *
155 * @param[in] adcp pointer to the @p ADCDriver object
156 *
157 * @notapi
158 */
159void adc_lld_stop(ADCDriver *adcp) {
160
161 /* If in ready state then disables the ADC clock.*/
162 if (adcp->state == ADC_READY) {
163#if STM32_ADC_USE_ADC1
164 if (&ADCD1 == adcp) {
165 ADC1->CR1 = 0;
166 ADC1->CR2 = 0;
167
168 dmaStreamFreeI(adcp->dmastp);
169 adcp->dmastp = NULL;
170
171 rccDisableADC1();
172 }
173#endif
174 }
175}
176
177/**
178 * @brief Starts an ADC conversion.
179 *
180 * @param[in] adcp pointer to the @p ADCDriver object
181 *
182 * @notapi
183 */
184void adc_lld_start_conversion(ADCDriver *adcp) {
185 uint32_t mode, cr2;
186 const ADCConversionGroup *grpp = adcp->grpp;
187
188 /* DMA setup.*/
189 mode = adcp->dmamode;
190 if (grpp->circular) {
191 mode |= STM32_DMA_CR_CIRC;
192 if (adcp->depth > 1) {
193 /* If circular buffer depth > 1, then the half transfer interrupt
194 is enabled in order to allow streaming processing.*/
195 mode |= STM32_DMA_CR_HTIE;
196 }
197 }
198 dmaStreamSetMemory0(adcp->dmastp, adcp->samples);
199 dmaStreamSetTransactionSize(adcp->dmastp, (uint32_t)grpp->num_channels *
200 (uint32_t)adcp->depth);
201 dmaStreamSetMode(adcp->dmastp, mode);
202 dmaStreamEnable(adcp->dmastp);
203
204 /* ADC setup.*/
205 adcp->adc->CR1 = grpp->cr1 | ADC_CR1_SCAN;
206 cr2 = grpp->cr2 | ADC_CR2_DMA | ADC_CR2_ADON;
207 if ((cr2 & (ADC_CR2_EXTTRIG | ADC_CR2_JEXTTRIG)) == 0)
208 cr2 |= ADC_CR2_CONT;
209 adcp->adc->CR2 = grpp->cr2 | cr2;
210 adcp->adc->SMPR1 = grpp->smpr1;
211 adcp->adc->SMPR2 = grpp->smpr2;
212 adcp->adc->SQR1 = grpp->sqr1;
213 adcp->adc->SQR2 = grpp->sqr2;
214 adcp->adc->SQR3 = grpp->sqr3;
215
216 /* ADC start by writing ADC_CR2_ADON a second time.*/
217 adcp->adc->CR2 = cr2;
218}
219
220/**
221 * @brief Stops an ongoing conversion.
222 *
223 * @param[in] adcp pointer to the @p ADCDriver object
224 *
225 * @notapi
226 */
227void adc_lld_stop_conversion(ADCDriver *adcp) {
228
229 dmaStreamDisable(adcp->dmastp);
230 adcp->adc->CR2 = 0;
231}
232
233#endif /* HAL_USE_ADC */
234
235/** @} */