diff options
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.c | 235 |
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__) | ||
39 | ADCDriver 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 | */ | ||
56 | static 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 | */ | ||
89 | void 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 | */ | ||
129 | void 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 | */ | ||
159 | void 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 | */ | ||
184 | void 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 | */ | ||
227 | void 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 | /** @} */ | ||