diff options
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.c | 236 |
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__) | ||
40 | ADCDriver 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 | */ | ||
57 | static 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 | */ | ||
90 | void 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 | */ | ||
130 | void 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 | */ | ||
160 | void 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 | */ | ||
185 | void 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 | */ | ||
228 | void 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 | /** @} */ | ||