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