diff options
Diffstat (limited to 'lib/chibios-contrib/os/hal/ports')
424 files changed, 159370 insertions, 0 deletions
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/driver.mk b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/driver.mk new file mode 100644 index 000000000..83db5502f --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/driver.mk | |||
@@ -0,0 +1,9 @@ | |||
1 | ifeq ($(USE_SMART_BUILD),yes) | ||
2 | ifneq ($(findstring HAL_USE_CAN TRUE,$(HALCONF)),) | ||
3 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.c | ||
4 | endif | ||
5 | else | ||
6 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.c | ||
7 | endif | ||
8 | |||
9 | PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/CAN | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.c b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.c new file mode 100644 index 000000000..4deb9dd0f --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.c | |||
@@ -0,0 +1,825 @@ | |||
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 CAN/hal_can_lld.c | ||
20 | * @brief GD32 CAN subsystem low level driver source. | ||
21 | * | ||
22 | * @addtogroup CAN | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #include "hal.h" | ||
27 | |||
28 | #if HAL_USE_CAN || defined(__DOXYGEN__) | ||
29 | |||
30 | /*===========================================================================*/ | ||
31 | /* Driver local definitions. */ | ||
32 | /*===========================================================================*/ | ||
33 | |||
34 | /* | ||
35 | * Addressing differences in the headers, they seem unable to agree on names. | ||
36 | */ | ||
37 | #if GD32_CAN_USE_CAN0 | ||
38 | #if !defined(CAN0) | ||
39 | #define CAN0 CAN | ||
40 | #endif | ||
41 | #endif | ||
42 | |||
43 | /*===========================================================================*/ | ||
44 | /* Driver exported variables. */ | ||
45 | /*===========================================================================*/ | ||
46 | |||
47 | /** @brief CAN0 driver identifier.*/ | ||
48 | #if GD32_CAN_USE_CAN0 || defined(__DOXYGEN__) | ||
49 | CANDriver CAND1; | ||
50 | #endif | ||
51 | |||
52 | /** @brief CAN1 driver identifier.*/ | ||
53 | #if GD32_CAN_USE_CAN1 || defined(__DOXYGEN__) | ||
54 | CANDriver CAND2; | ||
55 | #endif | ||
56 | |||
57 | /*===========================================================================*/ | ||
58 | /* Driver local variables and types. */ | ||
59 | /*===========================================================================*/ | ||
60 | |||
61 | /*===========================================================================*/ | ||
62 | /* Driver local functions. */ | ||
63 | /*===========================================================================*/ | ||
64 | /** | ||
65 | * @brief Programs the filters of CAN 1 and CAN 2. | ||
66 | * | ||
67 | * @param[in] canp pointer to the @p CANDriver object | ||
68 | * @param[in] can2sb number of the first filter assigned to CAN1 | ||
69 | * @param[in] num number of entries in the filters array, if zero then | ||
70 | * a default filter is programmed | ||
71 | * @param[in] cfp pointer to the filters array, can be @p NULL if | ||
72 | * (num == 0) | ||
73 | * | ||
74 | * @notapi | ||
75 | */ | ||
76 | static void can_lld_set_filters(CANDriver* canp, | ||
77 | uint32_t can2sb, | ||
78 | uint32_t num, | ||
79 | const CANFilter *cfp) { | ||
80 | |||
81 | #if GD32_CAN_USE_CAN1 | ||
82 | if (canp == &CAND2) { | ||
83 | /* Set handle to CAN0, because CAN0 manages the filters of CAN1.*/ | ||
84 | canp = &CAND1; | ||
85 | } | ||
86 | #endif | ||
87 | |||
88 | /* Temporarily enabling CAN clock.*/ | ||
89 | #if GD32_CAN_USE_CAN0 | ||
90 | if (canp == &CAND1) { | ||
91 | rcuEnableCAN0(true); | ||
92 | /* Filters initialization.*/ | ||
93 | canp->can->FCTL = (canp->can->FCTL & 0xFFFF0000) | CAN_FCTL_FLD; | ||
94 | canp->can->FCTL = (canp->can->FCTL & 0xFFFF0000) | (can2sb << 8) | CAN_FCTL_FLD; | ||
95 | } | ||
96 | #endif | ||
97 | |||
98 | if (num > 0) { | ||
99 | uint32_t i, fmask; | ||
100 | |||
101 | /* All filters cleared.*/ | ||
102 | canp->can->FW = 0; | ||
103 | canp->can->FMCFG = 0; | ||
104 | canp->can->FSCFG = 0; | ||
105 | canp->can->FAFIFO = 0; | ||
106 | |||
107 | #if GD32_CAN_USE_CAN0 | ||
108 | if (canp == &CAND1) { | ||
109 | for (i = 0; i < GD32_CAN_MAX_FILTERS; i++) { | ||
110 | canp->can->sFilterRegister[i].FR1 = 0; | ||
111 | canp->can->sFilterRegister[i].FR2 = 0; | ||
112 | } | ||
113 | } | ||
114 | #endif | ||
115 | |||
116 | /* Scanning the filters array.*/ | ||
117 | for (i = 0; i < num; i++) { | ||
118 | fmask = 1 << cfp->filter; | ||
119 | if (cfp->mode) | ||
120 | canp->can->FMCFG |= fmask; | ||
121 | if (cfp->scale) | ||
122 | canp->can->FSCFG |= fmask; | ||
123 | if (cfp->assignment) | ||
124 | canp->can->FAFIFO |= fmask; | ||
125 | canp->can->sFilterRegister[cfp->filter].FR1 = cfp->register1; | ||
126 | canp->can->sFilterRegister[cfp->filter].FR2 = cfp->register2; | ||
127 | canp->can->FW |= fmask; | ||
128 | cfp++; | ||
129 | } | ||
130 | } | ||
131 | else { | ||
132 | /* Setting up a single default filter that enables everything for both | ||
133 | CANs.*/ | ||
134 | canp->can->sFilterRegister[0].FR1 = 0; | ||
135 | canp->can->sFilterRegister[0].FR2 = 0; | ||
136 | #if GD32_CAN_USE_CAN1 | ||
137 | if (canp == &CAND1) { | ||
138 | canp->can->sFilterRegister[can2sb].FR1 = 0; | ||
139 | canp->can->sFilterRegister[can2sb].FR2 = 0; | ||
140 | } | ||
141 | #endif | ||
142 | canp->can->FMCFG = 0; | ||
143 | canp->can->FAFIFO = 0; | ||
144 | canp->can->FSCFG = 1; | ||
145 | canp->can->FW = 1; | ||
146 | #if GD32_CAN_USE_CAN1 | ||
147 | if (canp == &CAND1) { | ||
148 | canp->can->FSCFG |= 1 << can2sb; | ||
149 | canp->can->FW |= 1 << can2sb; | ||
150 | } | ||
151 | #endif | ||
152 | } | ||
153 | canp->can->FCTL &= ~CAN_FCTL_FLD; | ||
154 | |||
155 | /* Clock disabled, it will be enabled again in can_lld_start().*/ | ||
156 | /* Temporarily enabling CAN clock.*/ | ||
157 | #if GD32_CAN_USE_CAN0 | ||
158 | if (canp == &CAND1) { | ||
159 | rcuDisableCAN0(); | ||
160 | } | ||
161 | #endif | ||
162 | } | ||
163 | |||
164 | /** | ||
165 | * @brief Common TX ISR handler. | ||
166 | * | ||
167 | * @param[in] canp pointer to the @p CANDriver object | ||
168 | * | ||
169 | * @notapi | ||
170 | */ | ||
171 | static void can_lld_tx_handler(CANDriver *canp) { | ||
172 | uint32_t tstat; | ||
173 | eventflags_t flags; | ||
174 | |||
175 | /* Clearing IRQ sources.*/ | ||
176 | tstat = canp->can->TSTAT; | ||
177 | canp->can->TSTAT = tstat; | ||
178 | |||
179 | /* Flags to be signaled through the TX event source.*/ | ||
180 | flags = 0U; | ||
181 | |||
182 | /* Checking mailbox 0.*/ | ||
183 | if ((tstat & CAN_TSTAT_MTF0) != 0U) { | ||
184 | if ((tstat & (CAN_TSTAT_MAL0 | CAN_TSTAT_MTE0)) != 0U) { | ||
185 | flags |= CAN_MAILBOX_TO_MASK(1U) << 16U; | ||
186 | } | ||
187 | else { | ||
188 | flags |= CAN_MAILBOX_TO_MASK(1U); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | /* Checking mailbox 1.*/ | ||
193 | if ((tstat & CAN_TSTAT_MTF1) != 0U) { | ||
194 | if ((tstat & (CAN_TSTAT_MAL1 | CAN_TSTAT_MTE1)) != 0U) { | ||
195 | flags |= CAN_MAILBOX_TO_MASK(2U) << 16U; | ||
196 | } | ||
197 | else { | ||
198 | flags |= CAN_MAILBOX_TO_MASK(2U); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | /* Checking mailbox 2.*/ | ||
203 | if ((tstat & CAN_TSTAT_MTF2) != 0U) { | ||
204 | if ((tstat & (CAN_TSTAT_MAL2 | CAN_TSTAT_MTE2)) != 0U) { | ||
205 | flags |= CAN_MAILBOX_TO_MASK(3U) << 16U; | ||
206 | } | ||
207 | else { | ||
208 | flags |= CAN_MAILBOX_TO_MASK(3U); | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* Signaling flags and waking up threads waiting for a transmission slot.*/ | ||
213 | _can_tx_empty_isr(canp, flags); | ||
214 | } | ||
215 | |||
216 | /** | ||
217 | * @brief Common RX0 ISR handler. | ||
218 | * | ||
219 | * @param[in] canp pointer to the @p CANDriver object | ||
220 | * | ||
221 | * @notapi | ||
222 | */ | ||
223 | static void can_lld_rx0_handler(CANDriver *canp) { | ||
224 | uint32_t rfifo0; | ||
225 | |||
226 | rfifo0 = canp->can->RFIFO0; | ||
227 | if ((rfifo0 & CAN_RFIFO0_RFL0) > 0) { | ||
228 | /* No more receive events until the queue 0 has been emptied.*/ | ||
229 | canp->can->INTEN &= ~CAN_INTEN_RFNEIE0; | ||
230 | _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(1U)); | ||
231 | } | ||
232 | if ((rfifo0 & CAN_RFIFO0_RFO0) > 0) { | ||
233 | /* Overflow events handling.*/ | ||
234 | canp->can->RFIFO0 = CAN_RFIFO0_RFO0; | ||
235 | _can_error_isr(canp, CAN_OVERFLOW_ERROR); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * @brief Common RX1 ISR handler. | ||
241 | * | ||
242 | * @param[in] canp pointer to the @p CANDriver object | ||
243 | * | ||
244 | * @notapi | ||
245 | */ | ||
246 | static void can_lld_rx1_handler(CANDriver *canp) { | ||
247 | uint32_t rfifo1; | ||
248 | |||
249 | rfifo1 = canp->can->RFIFO1; | ||
250 | if ((rfifo1 & CAN_RFIFO1_RFL1) > 0) { | ||
251 | /* No more receive events until the queue 0 has been emptied.*/ | ||
252 | canp->can->INTEN &= ~CAN_INTEN_RFNEIE1; | ||
253 | _can_rx_full_isr(canp, CAN_MAILBOX_TO_MASK(2U)); | ||
254 | } | ||
255 | if ((rfifo1 & CAN_RFIFO1_RFO1) > 0) { | ||
256 | /* Overflow events handling.*/ | ||
257 | canp->can->RFIFO1 = CAN_RFIFO1_RFO1; | ||
258 | _can_error_isr(canp, CAN_OVERFLOW_ERROR); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * @brief Common SCE ISR handler. | ||
264 | * | ||
265 | * @param[in] canp pointer to the @p CANDriver object | ||
266 | * | ||
267 | * @notapi | ||
268 | */ | ||
269 | static void can_lld_sce_handler(CANDriver *canp) { | ||
270 | uint32_t stat; | ||
271 | |||
272 | /* Clearing IRQ sources.*/ | ||
273 | stat = canp->can->STAT; | ||
274 | canp->can->STAT = stat; | ||
275 | |||
276 | /* Wakeup event.*/ | ||
277 | #if CAN_USE_SLEEP_MODE | ||
278 | if (stat & CAN_STAT_WUIF) { | ||
279 | canp->state = CAN_READY; | ||
280 | canp->can->CTL &= ~CAN_CTL_SLPWMOD; | ||
281 | _can_wakeup_isr(canp); | ||
282 | } | ||
283 | #endif /* CAN_USE_SLEEP_MODE */ | ||
284 | /* Error event.*/ | ||
285 | if (stat & CAN_STAT_ERRIF) { | ||
286 | eventflags_t flags; | ||
287 | uint32_t err = canp->can->ERR; | ||
288 | |||
289 | #if GD32_CAN_REPORT_ALL_ERRORS | ||
290 | flags = (eventflags_t)(err & 7); | ||
291 | if ((err & CAN_ERR_ERRN) > 0) | ||
292 | flags |= CAN_FRAMING_ERROR; | ||
293 | #else | ||
294 | flags = 0; | ||
295 | #endif | ||
296 | |||
297 | /* The content of the ESR register is copied unchanged in the upper | ||
298 | half word of the listener flags mask.*/ | ||
299 | _can_error_isr(canp, flags | (eventflags_t)(err << 16U)); | ||
300 | } | ||
301 | } | ||
302 | |||
303 | /*===========================================================================*/ | ||
304 | /* Driver interrupt handlers. */ | ||
305 | /*===========================================================================*/ | ||
306 | |||
307 | #if GD32_CAN_USE_CAN0 || defined(__DOXYGEN__) | ||
308 | #if !defined(GD32_CAN0_TX_HANDLER) | ||
309 | #error "GD32_CAN0_TX_HANDLER not defined" | ||
310 | #endif | ||
311 | #if !defined(GD32_CAN0_RX0_HANDLER) | ||
312 | #error "GD32_CAN0_RX0_HANDLER not defined" | ||
313 | #endif | ||
314 | #if !defined(GD32_CAN0_RX1_HANDLER) | ||
315 | #error "GD32_CAN0_RX1_HANDLER not defined" | ||
316 | #endif | ||
317 | #if !defined(GD32_CAN0_EWMC_HANDLER) | ||
318 | #error "GD32_CAN0_EWMC_HANDLER not defined" | ||
319 | #endif | ||
320 | |||
321 | /** | ||
322 | * @brief CAN0 TX interrupt handler. | ||
323 | * | ||
324 | * @isr | ||
325 | */ | ||
326 | OSAL_IRQ_HANDLER(GD32_CAN0_TX_HANDLER) { | ||
327 | |||
328 | OSAL_IRQ_PROLOGUE(); | ||
329 | |||
330 | can_lld_tx_handler(&CAND1); | ||
331 | |||
332 | OSAL_IRQ_EPILOGUE(); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * @brief CAN0 RX0 interrupt handler. | ||
337 | * | ||
338 | * @isr | ||
339 | */ | ||
340 | OSAL_IRQ_HANDLER(GD32_CAN0_RX0_HANDLER) { | ||
341 | |||
342 | OSAL_IRQ_PROLOGUE(); | ||
343 | |||
344 | can_lld_rx0_handler(&CAND1); | ||
345 | |||
346 | OSAL_IRQ_EPILOGUE(); | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * @brief CAN0 RX1 interrupt handler. | ||
351 | * | ||
352 | * @isr | ||
353 | */ | ||
354 | OSAL_IRQ_HANDLER(GD32_CAN0_RX1_HANDLER) { | ||
355 | |||
356 | OSAL_IRQ_PROLOGUE(); | ||
357 | |||
358 | can_lld_rx1_handler(&CAND1); | ||
359 | |||
360 | OSAL_IRQ_EPILOGUE(); | ||
361 | } | ||
362 | |||
363 | /** | ||
364 | * @brief CAN0 SCE interrupt handler. | ||
365 | * | ||
366 | * @isr | ||
367 | */ | ||
368 | OSAL_IRQ_HANDLER(GD32_CAN0_EWMC_HANDLER) { | ||
369 | |||
370 | OSAL_IRQ_PROLOGUE(); | ||
371 | |||
372 | can_lld_sce_handler(&CAND1); | ||
373 | |||
374 | OSAL_IRQ_EPILOGUE(); | ||
375 | } | ||
376 | #endif /* GD32_CAN_USE_CAN0 */ | ||
377 | |||
378 | #if GD32_CAN_USE_CAN1 || defined(__DOXYGEN__) | ||
379 | #if !defined(GD32_CAN0_TX_HANDLER) | ||
380 | #error "GD32_CAN0_TX_HANDLER not defined" | ||
381 | #endif | ||
382 | #if !defined(GD32_CAN0_RX0_HANDLER) | ||
383 | #error "GD32_CAN0_RX0_HANDLER not defined" | ||
384 | #endif | ||
385 | #if !defined(GD32_CAN0_RX1_HANDLER) | ||
386 | #error "GD32_CAN0_RX1_HANDLER not defined" | ||
387 | #endif | ||
388 | #if !defined(GD32_CAN0_EWMC_HANDLER) | ||
389 | #error "GD32_CAN0_EWMC_HANDLER not defined" | ||
390 | #endif | ||
391 | |||
392 | /** | ||
393 | * @brief CAN1 TX interrupt handler. | ||
394 | * | ||
395 | * @isr | ||
396 | */ | ||
397 | OSAL_IRQ_HANDLER(GD32_CAN0_TX_HANDLER) { | ||
398 | |||
399 | OSAL_IRQ_PROLOGUE(); | ||
400 | |||
401 | can_lld_tx_handler(&CAND2); | ||
402 | |||
403 | OSAL_IRQ_EPILOGUE(); | ||
404 | } | ||
405 | |||
406 | /** | ||
407 | * @brief CAN1 RX0 interrupt handler. | ||
408 | * | ||
409 | * @isr | ||
410 | */ | ||
411 | OSAL_IRQ_HANDLER(GD32_CAN0_RX0_HANDLER) { | ||
412 | |||
413 | OSAL_IRQ_PROLOGUE(); | ||
414 | |||
415 | can_lld_rx0_handler(&CAND2); | ||
416 | |||
417 | OSAL_IRQ_EPILOGUE(); | ||
418 | } | ||
419 | |||
420 | /** | ||
421 | * @brief CAN1 RX1 interrupt handler. | ||
422 | * | ||
423 | * @isr | ||
424 | */ | ||
425 | OSAL_IRQ_HANDLER(GD32_CAN0_RX1_HANDLER) { | ||
426 | |||
427 | OSAL_IRQ_PROLOGUE(); | ||
428 | |||
429 | can_lld_rx1_handler(&CAND2); | ||
430 | |||
431 | OSAL_IRQ_EPILOGUE(); | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * @brief CAN1 SCE interrupt handler. | ||
436 | * | ||
437 | * @isr | ||
438 | */ | ||
439 | OSAL_IRQ_HANDLER(GD32_CAN0_EWMC_HANDLER) { | ||
440 | |||
441 | OSAL_IRQ_PROLOGUE(); | ||
442 | |||
443 | can_lld_sce_handler(&CAND2); | ||
444 | |||
445 | OSAL_IRQ_EPILOGUE(); | ||
446 | } | ||
447 | #endif /* GD32_CAN_USE_CAN1 */ | ||
448 | |||
449 | /*===========================================================================*/ | ||
450 | /* Driver exported functions. */ | ||
451 | /*===========================================================================*/ | ||
452 | |||
453 | /** | ||
454 | * @brief Low level CAN driver initialization. | ||
455 | * | ||
456 | * @notapi | ||
457 | */ | ||
458 | void can_lld_init(void) { | ||
459 | |||
460 | #if GD32_CAN_USE_CAN0 | ||
461 | /* Driver initialization.*/ | ||
462 | canObjectInit(&CAND1); | ||
463 | CAND1.can = CAN0; | ||
464 | eclicEnableVector(GD32_CAN0_TX_NUMBER, GD32_CAN_CAN0_IRQ_PRIORITY, GD32_CAN_CAN0_IRQ_TRIGGER); | ||
465 | eclicEnableVector(GD32_CAN0_RX0_NUMBER, GD32_CAN_CAN0_IRQ_PRIORITY, GD32_CAN_CAN0_IRQ_TRIGGER); | ||
466 | eclicEnableVector(GD32_CAN0_RX1_NUMBER, GD32_CAN_CAN0_IRQ_PRIORITY, GD32_CAN_CAN0_IRQ_TRIGGER); | ||
467 | eclicEnableVector(GD32_CAN0_EWMC_NUMBER, GD32_CAN_CAN0_IRQ_PRIORITY, GD32_CAN_CAN0_IRQ_TRIGGER); | ||
468 | #endif | ||
469 | |||
470 | #if GD32_CAN_USE_CAN1 | ||
471 | /* Driver initialization.*/ | ||
472 | canObjectInit(&CAND2); | ||
473 | CAND2.can = CAN1; | ||
474 | eclicEnableVector(GD32_CAN0_TX_NUMBER, GD32_CAN_CAN1_IRQ_PRIORITY, GD32_CAN_CAN1_IRQ_TRIGGER); | ||
475 | eclicEnableVector(GD32_CAN0_RX0_NUMBER, GD32_CAN_CAN1_IRQ_PRIORITY, GD32_CAN_CAN1_IRQ_TRIGGER); | ||
476 | eclicEnableVector(GD32_CAN0_RX1_NUMBER, GD32_CAN_CAN1_IRQ_PRIORITY, GD32_CAN_CAN1_IRQ_TRIGGER); | ||
477 | eclicEnableVector(GD32_CAN0_EWMC_NUMBER, GD32_CAN_CAN1_IRQ_PRIORITY, GD32_CAN_CAN1_IRQ_TRIGGER); | ||
478 | #endif | ||
479 | |||
480 | /* Filters initialization.*/ | ||
481 | #if GD32_CAN_USE_CAN0 | ||
482 | #if GD32_HAS_CAN1 | ||
483 | can_lld_set_filters(&CAND1, GD32_CAN_MAX_FILTERS / 2, 0, NULL); | ||
484 | #else | ||
485 | can_lld_set_filters(&CAND1, GD32_CAN_MAX_FILTERS, 0, NULL); | ||
486 | #endif | ||
487 | #endif | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * @brief Configures and activates the CAN peripheral. | ||
492 | * | ||
493 | * @param[in] canp pointer to the @p CANDriver object | ||
494 | * | ||
495 | * @notapi | ||
496 | */ | ||
497 | void can_lld_start(CANDriver *canp) { | ||
498 | |||
499 | /* Clock activation.*/ | ||
500 | #if GD32_CAN_USE_CAN0 | ||
501 | if (&CAND1 == canp) { | ||
502 | rcuEnableCAN0(true); | ||
503 | } | ||
504 | #endif | ||
505 | |||
506 | #if GD32_CAN_USE_CAN1 | ||
507 | if (&CAND2 == canp) { | ||
508 | rcuEnableCAN0(true); /* CAN 2 requires CAN0, so enabling it first.*/ | ||
509 | rcuEnableCAN1(true); | ||
510 | } | ||
511 | #endif | ||
512 | |||
513 | /* Configuring CAN. */ | ||
514 | canp->can->CTL = CAN_CTL_IWMOD; | ||
515 | while ((canp->can->STAT & CAN_STAT_IWS) == 0) | ||
516 | osalThreadSleepS(1); | ||
517 | canp->can->BT = canp->config->bt; | ||
518 | canp->can->CTL = canp->config->ctl; | ||
519 | |||
520 | /* Interrupt sources initialization.*/ | ||
521 | #if GD32_CAN_REPORT_ALL_ERRORS | ||
522 | canp->can->INTEN = CAN_INTEN_TMEIE | CAN_INTEN_RFNEIE0 | CAN_INTEN_RFNEIE1 | | ||
523 | CAN_INTEN_WIE | CAN_INTEN_ERRIE | CAN_INTEN_ERRNIE | | ||
524 | CAN_INTEN_BOIE | CAN_INTEN_PERRIE | CAN_INTEN_WERRIE | | ||
525 | CAN_INTEN_RFOIE0 | CAN_INTEN_RFOIE1; | ||
526 | #else | ||
527 | canp->can->INTEN = CAN_INTEN_TMEIE | CAN_INTEN_RFNEIE0 | CAN_INTEN_RFNEIE1 | | ||
528 | CAN_INTEN_WIE | CAN_INTEN_ERRIE | | ||
529 | CAN_INTEN_BOIE | CAN_INTEN_PERRIE | CAN_INTEN_WERRIE | | ||
530 | CAN_INTEN_RFOIE0 | CAN_INTEN_RFOIE1; | ||
531 | #endif | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * @brief Deactivates the CAN peripheral. | ||
536 | * | ||
537 | * @param[in] canp pointer to the @p CANDriver object | ||
538 | * | ||
539 | * @notapi | ||
540 | */ | ||
541 | void can_lld_stop(CANDriver *canp) { | ||
542 | |||
543 | /* If in ready state then disables the CAN peripheral.*/ | ||
544 | if (canp->state == CAN_READY) { | ||
545 | #if GD32_CAN_USE_CAN0 | ||
546 | if (&CAND1 == canp) { | ||
547 | CAN0->CTL = 0x00010002; /* Register reset value. */ | ||
548 | CAN0->INTEN = 0x00000000; /* All sources disabled. */ | ||
549 | #if GD32_CAN_USE_CAN1 | ||
550 | /* If CAND2 is stopped then CAN0 clock is stopped here.*/ | ||
551 | if (CAND2.state == CAN_STOP) | ||
552 | #endif | ||
553 | { | ||
554 | rcuDisableCAN0(); | ||
555 | } | ||
556 | } | ||
557 | #endif | ||
558 | |||
559 | #if GD32_CAN_USE_CAN1 | ||
560 | if (&CAND2 == canp) { | ||
561 | CAN1->CTL = 0x00010002; /* Register reset value. */ | ||
562 | CAN1->INTEN = 0x00000000; /* All sources disabled. */ | ||
563 | #if GD32_CAN_USE_CAN0 | ||
564 | /* If CAND1 is stopped then CAN0 clock is stopped here.*/ | ||
565 | if (CAND1.state == CAN_STOP) | ||
566 | #endif | ||
567 | { | ||
568 | rcuDisableCAN0(); | ||
569 | } | ||
570 | rcuDisableCAN1(); | ||
571 | } | ||
572 | #endif | ||
573 | } | ||
574 | } | ||
575 | |||
576 | /** | ||
577 | * @brief Determines whether a frame can be transmitted. | ||
578 | * | ||
579 | * @param[in] canp pointer to the @p CANDriver object | ||
580 | * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox | ||
581 | * | ||
582 | * @return The queue space availability. | ||
583 | * @retval false no space in the transmit queue. | ||
584 | * @retval true transmit slot available. | ||
585 | * | ||
586 | * @notapi | ||
587 | */ | ||
588 | bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox) { | ||
589 | |||
590 | switch (mailbox) { | ||
591 | case CAN_ANY_MAILBOX: | ||
592 | return (canp->can->TSTAT & CAN_TSTAT_TME) != 0; | ||
593 | case 1: | ||
594 | return (canp->can->TSTAT & CAN_TSTAT_TME0) != 0; | ||
595 | case 2: | ||
596 | return (canp->can->TSTAT & CAN_TSTAT_TME1) != 0; | ||
597 | case 3: | ||
598 | return (canp->can->TSTAT & CAN_TSTAT_TME2) != 0; | ||
599 | default: | ||
600 | return false; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | /** | ||
605 | * @brief Inserts a frame into the transmit queue. | ||
606 | * | ||
607 | * @param[in] canp pointer to the @p CANDriver object | ||
608 | * @param[in] ctfp pointer to the CAN frame to be transmitted | ||
609 | * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox | ||
610 | * | ||
611 | * @notapi | ||
612 | */ | ||
613 | void can_lld_transmit(CANDriver *canp, | ||
614 | canmbx_t mailbox, | ||
615 | const CANTxFrame *ctfp) { | ||
616 | uint32_t tmi; | ||
617 | CAN_TxMailBox_TypeDef *tmbp; | ||
618 | |||
619 | /* Pointer to a free transmission mailbox.*/ | ||
620 | switch (mailbox) { | ||
621 | case CAN_ANY_MAILBOX: | ||
622 | tmbp = &canp->can->sTxMailBox[(canp->can->TSTAT & CAN_TSTAT_NUM) >> 24]; | ||
623 | break; | ||
624 | case 1: | ||
625 | tmbp = &canp->can->sTxMailBox[0]; | ||
626 | break; | ||
627 | case 2: | ||
628 | tmbp = &canp->can->sTxMailBox[1]; | ||
629 | break; | ||
630 | case 3: | ||
631 | tmbp = &canp->can->sTxMailBox[2]; | ||
632 | break; | ||
633 | default: | ||
634 | return; | ||
635 | } | ||
636 | |||
637 | /* Preparing the message.*/ | ||
638 | if (ctfp->IDE) | ||
639 | tmi = ((uint32_t)ctfp->EID << 3) | ((uint32_t)ctfp->RTR << 1) | | ||
640 | CAN_TMI0_FF; | ||
641 | else | ||
642 | tmi = ((uint32_t)ctfp->SID << 21) | ((uint32_t)ctfp->RTR << 1); | ||
643 | tmbp->TMP = ctfp->DLC; | ||
644 | tmbp->TMDATA0 = ctfp->data32[0]; | ||
645 | tmbp->TMDATA1 = ctfp->data32[1]; | ||
646 | tmbp->TMI = tmi | CAN_TMI0_TEN; | ||
647 | } | ||
648 | |||
649 | /** | ||
650 | * @brief Determines whether a frame has been received. | ||
651 | * | ||
652 | * @param[in] canp pointer to the @p CANDriver object | ||
653 | * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox | ||
654 | * | ||
655 | * @return The queue space availability. | ||
656 | * @retval false no space in the transmit queue. | ||
657 | * @retval true transmit slot available. | ||
658 | * | ||
659 | * @notapi | ||
660 | */ | ||
661 | bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox) { | ||
662 | |||
663 | switch (mailbox) { | ||
664 | case CAN_ANY_MAILBOX: | ||
665 | return ((canp->can->RFIFO0 & CAN_RFIFO0_RFL0) != 0 || | ||
666 | (canp->can->RFIFO1 & CAN_RFIFO1_RFL1) != 0); | ||
667 | case 1: | ||
668 | return (canp->can->RFIFO0 & CAN_RFIFO0_RFL0) != 0; | ||
669 | case 2: | ||
670 | return (canp->can->RFIFO1 & CAN_RFIFO1_RFL1) != 0; | ||
671 | default: | ||
672 | return false; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | /** | ||
677 | * @brief Receives a frame from the input queue. | ||
678 | * | ||
679 | * @param[in] canp pointer to the @p CANDriver object | ||
680 | * @param[in] mailbox mailbox number, @p CAN_ANY_MAILBOX for any mailbox | ||
681 | * @param[out] crfp pointer to the buffer where the CAN frame is copied | ||
682 | * | ||
683 | * @notapi | ||
684 | */ | ||
685 | void can_lld_receive(CANDriver *canp, | ||
686 | canmbx_t mailbox, | ||
687 | CANRxFrame *crfp) { | ||
688 | uint32_t rfifomi, rfifomp; | ||
689 | |||
690 | if (mailbox == CAN_ANY_MAILBOX) { | ||
691 | if ((canp->can->RFIFO0 & CAN_RFIFO0_RFL0) != 0) | ||
692 | mailbox = 1; | ||
693 | else if ((canp->can->RFIFO1 & CAN_RFIFO1_RFL1) != 0) | ||
694 | mailbox = 2; | ||
695 | else { | ||
696 | /* Should not happen, do nothing.*/ | ||
697 | return; | ||
698 | } | ||
699 | } | ||
700 | switch (mailbox) { | ||
701 | case 1: | ||
702 | /* Fetches the message.*/ | ||
703 | rfifomi = canp->can->sFIFOMailBox[0].RFIFOMI; | ||
704 | rfifomp = canp->can->sFIFOMailBox[0].RFIFOMP; | ||
705 | crfp->data32[0] = canp->can->sFIFOMailBox[0].RFIFOMDATA0; | ||
706 | crfp->data32[1] = canp->can->sFIFOMailBox[0].RFIFOMDATA1; | ||
707 | |||
708 | /* Releases the mailbox.*/ | ||
709 | canp->can->RFIFO0 = CAN_RFIFO0_RFD0; | ||
710 | |||
711 | /* If the queue is empty re-enables the interrupt in order to generate | ||
712 | events again.*/ | ||
713 | if ((canp->can->RFIFO0 & CAN_RFIFO0_RFL0) == 0) | ||
714 | canp->can->INTEN |= CAN_INTEN_RFNEIE0; | ||
715 | break; | ||
716 | case 2: | ||
717 | /* Fetches the message.*/ | ||
718 | rfifomi = canp->can->sFIFOMailBox[1].RFIFOMI; | ||
719 | rfifomp = canp->can->sFIFOMailBox[1].RFIFOMP; | ||
720 | crfp->data32[0] = canp->can->sFIFOMailBox[1].RFIFOMDATA0; | ||
721 | crfp->data32[1] = canp->can->sFIFOMailBox[1].RFIFOMDATA1; | ||
722 | |||
723 | /* Releases the mailbox.*/ | ||
724 | canp->can->RFIFO1 = CAN_RFIFO1_RFD1; | ||
725 | |||
726 | /* If the queue is empty re-enables the interrupt in order to generate | ||
727 | events again.*/ | ||
728 | if ((canp->can->RFIFO1 & CAN_RFIFO1_RFL1) == 0) | ||
729 | canp->can->INTEN |= CAN_INTEN_RFNEIE1; | ||
730 | break; | ||
731 | default: | ||
732 | /* Should not happen, do nothing.*/ | ||
733 | return; | ||
734 | } | ||
735 | |||
736 | /* Decodes the various fields in the RX frame.*/ | ||
737 | crfp->RTR = (rfifomi & CAN_RFIFOMI0_FT) >> 1; | ||
738 | crfp->IDE = (rfifomi & CAN_RFIFOMI0_FF) >> 2; | ||
739 | if (crfp->IDE) | ||
740 | crfp->EID = rfifomi >> 3; | ||
741 | else | ||
742 | crfp->SID = rfifomi >> 21; | ||
743 | crfp->DLC = rfifomp & CAN_RFIFOMP0_DLENC; | ||
744 | crfp->FMI = (uint8_t)(rfifomp >> 8); | ||
745 | crfp->TIME = (uint16_t)(rfifomp >> 16); | ||
746 | } | ||
747 | |||
748 | /** | ||
749 | * @brief Tries to abort an ongoing transmission. | ||
750 | * | ||
751 | * @param[in] canp pointer to the @p CANDriver object | ||
752 | * @param[in] mailbox mailbox number | ||
753 | * | ||
754 | * @notapi | ||
755 | */ | ||
756 | void can_lld_abort(CANDriver *canp, | ||
757 | canmbx_t mailbox) { | ||
758 | |||
759 | canp->can->TSTAT = 128U << ((mailbox - 1U) * 8U); | ||
760 | } | ||
761 | |||
762 | #if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__) | ||
763 | /** | ||
764 | * @brief Enters the sleep mode. | ||
765 | * | ||
766 | * @param[in] canp pointer to the @p CANDriver object | ||
767 | * | ||
768 | * @notapi | ||
769 | */ | ||
770 | void can_lld_sleep(CANDriver *canp) { | ||
771 | |||
772 | canp->can->CTL |= CAN_CTL_SLPWMOD; | ||
773 | } | ||
774 | |||
775 | /** | ||
776 | * @brief Enforces leaving the sleep mode. | ||
777 | * | ||
778 | * @param[in] canp pointer to the @p CANDriver object | ||
779 | * | ||
780 | * @notapi | ||
781 | */ | ||
782 | void can_lld_wakeup(CANDriver *canp) { | ||
783 | |||
784 | canp->can->CTL &= ~CAN_CTL_SLPWMOD; | ||
785 | } | ||
786 | #endif /* CAN_USE_SLEEP_MODE */ | ||
787 | |||
788 | /** | ||
789 | * @brief Programs the filters. | ||
790 | * @note This is an GD32-specific API. | ||
791 | * | ||
792 | * @param[in] canp pointer to the @p CANDriver object | ||
793 | * @param[in] can2sb number of the first filter assigned to CAN1 | ||
794 | * @param[in] num number of entries in the filters array, if zero then | ||
795 | * a default filter is programmed | ||
796 | * @param[in] cfp pointer to the filters array, can be @p NULL if | ||
797 | * (num == 0) | ||
798 | * | ||
799 | * @api | ||
800 | */ | ||
801 | void canGD32SetFilters(CANDriver *canp, uint32_t can2sb, | ||
802 | uint32_t num, const CANFilter *cfp) { | ||
803 | |||
804 | #if GD32_CAN_USE_CAN1 | ||
805 | osalDbgCheck((can2sb <= GD32_CAN_MAX_FILTERS) && | ||
806 | (num <= GD32_CAN_MAX_FILTERS)); | ||
807 | #endif | ||
808 | |||
809 | #if GD32_CAN_USE_CAN0 | ||
810 | osalDbgAssert(CAND1.state == CAN_STOP, "invalid state"); | ||
811 | #endif | ||
812 | #if GD32_CAN_USE_CAN1 | ||
813 | osalDbgAssert(CAND2.state == CAN_STOP, "invalid state"); | ||
814 | #endif | ||
815 | |||
816 | #if GD32_CAN_USE_CAN0 | ||
817 | if (canp == &CAND1) { | ||
818 | can_lld_set_filters(canp, can2sb, num, cfp); | ||
819 | } | ||
820 | #endif | ||
821 | } | ||
822 | |||
823 | #endif /* HAL_USE_CAN */ | ||
824 | |||
825 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.h b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.h new file mode 100644 index 000000000..f91ff1ba0 --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CAN/hal_can_lld.h | |||
@@ -0,0 +1,455 @@ | |||
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 CAN/hal_can_lld.h | ||
20 | * @brief GD32 CAN subsystem low level driver header. | ||
21 | * | ||
22 | * @addtogroup CAN | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #ifndef HAL_CAN_LLD_H | ||
27 | #define HAL_CAN_LLD_H | ||
28 | |||
29 | #if HAL_USE_CAN || defined(__DOXYGEN__) | ||
30 | |||
31 | /*===========================================================================*/ | ||
32 | /* Driver constants. */ | ||
33 | /*===========================================================================*/ | ||
34 | |||
35 | /* | ||
36 | * The following macros from the ST header file are replaced with better | ||
37 | * equivalents. | ||
38 | */ | ||
39 | #undef CAN_BT_BAUDPSC | ||
40 | #undef CAN_BT_BS1 | ||
41 | #undef CAN_BT_BS2 | ||
42 | #undef CAN_BT_SJW | ||
43 | |||
44 | /** | ||
45 | * @brief This switch defines whether the driver implementation supports | ||
46 | * a low power switch mode with automatic an wakeup feature. | ||
47 | */ | ||
48 | #define CAN_SUPPORTS_SLEEP TRUE | ||
49 | |||
50 | /** | ||
51 | * @brief This implementation supports three transmit mailboxes. | ||
52 | */ | ||
53 | #define CAN_TX_MAILBOXES 3 | ||
54 | |||
55 | /** | ||
56 | * @brief This implementation supports two receive mailboxes. | ||
57 | */ | ||
58 | #define CAN_RX_MAILBOXES 2 | ||
59 | |||
60 | /** | ||
61 | * @name CAN registers helper macros | ||
62 | * @{ | ||
63 | */ | ||
64 | #define CAN_BT_BAUDPSC(n) (n) /**< @brief BRP field macro.*/ | ||
65 | #define CAN_BT_BS1(n) ((n) << 16) /**< @brief TS1 field macro.*/ | ||
66 | #define CAN_BT_BS2(n) ((n) << 20) /**< @brief TS2 field macro.*/ | ||
67 | #define CAN_BT_SJW(n) ((n) << 24) /**< @brief SJW field macro.*/ | ||
68 | |||
69 | #define CAN_IDE_STD 0 /**< @brief Standard id. */ | ||
70 | #define CAN_IDE_EXT 1 /**< @brief Extended id. */ | ||
71 | |||
72 | #define CAN_RTR_DATA 0 /**< @brief Data frame. */ | ||
73 | #define CAN_RTR_REMOTE 1 /**< @brief Remote frame. */ | ||
74 | /** @} */ | ||
75 | |||
76 | /*===========================================================================*/ | ||
77 | /* Driver pre-compile time settings. */ | ||
78 | /*===========================================================================*/ | ||
79 | |||
80 | /** | ||
81 | * @name Configuration options | ||
82 | * @{ | ||
83 | */ | ||
84 | /** | ||
85 | * @brief CAN pedantic errors report. | ||
86 | * @details Use of this option is IRQ-intensive. | ||
87 | */ | ||
88 | #if !defined(GD32_CAN_REPORT_ALL_ERRORS) || defined(__DOXYGEN__) | ||
89 | #define GD32_CAN_REPORT_ALL_ERRORS FALSE | ||
90 | #endif | ||
91 | |||
92 | /** | ||
93 | * @brief CAN0 driver enable switch. | ||
94 | * @details If set to @p TRUE the support for CAN0 is included. | ||
95 | */ | ||
96 | #if !defined(GD32_CAN_USE_CAN0) || defined(__DOXYGEN__) | ||
97 | #define GD32_CAN_USE_CAN0 FALSE | ||
98 | #endif | ||
99 | |||
100 | /** | ||
101 | * @brief CAN1 driver enable switch. | ||
102 | * @details If set to @p TRUE the support for CAN1 is included. | ||
103 | */ | ||
104 | #if !defined(GD32_CAN_USE_CAN1) || defined(__DOXYGEN__) | ||
105 | #define GD32_CAN_USE_CAN1 FALSE | ||
106 | #endif | ||
107 | |||
108 | /** | ||
109 | * @brief CAN0 interrupt priority level setting. | ||
110 | */ | ||
111 | #if !defined(GD32_CAN_CAN0_IRQ_PRIORITY) || defined(__DOXYGEN__) | ||
112 | #define GD32_CAN_CAN0_IRQ_PRIORITY 11 | ||
113 | #endif | ||
114 | /** @} */ | ||
115 | |||
116 | /** | ||
117 | * @brief CAN1 interrupt priority level setting. | ||
118 | */ | ||
119 | #if !defined(GD32_CAN_CAN1_IRQ_PRIORITY) || defined(__DOXYGEN__) | ||
120 | #define GD32_CAN_CAN1_IRQ_PRIORITY 11 | ||
121 | #endif | ||
122 | |||
123 | /** | ||
124 | * @brief CAN0 interrupt trigger setting. | ||
125 | */ | ||
126 | #if !defined(GD32_CAN_CAN0_IRQ_TRIGGER) || defined(__DOXYGEN__) | ||
127 | #define GD32_CAN_CAN0_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
128 | #endif | ||
129 | /** @} */ | ||
130 | |||
131 | /** | ||
132 | * @brief CAN1 interrupt trigger setting. | ||
133 | */ | ||
134 | #if !defined(GD32_CAN_CAN1_IRQ_TRIGGER) || defined(__DOXYGEN__) | ||
135 | #define GD32_CAN_CAN1_IRQ_TRIGGER ECLIC_TRIGGER_DEFAULT | ||
136 | #endif | ||
137 | /** @} */ | ||
138 | |||
139 | /*===========================================================================*/ | ||
140 | /* Derived constants and error checks. */ | ||
141 | /*===========================================================================*/ | ||
142 | |||
143 | #if !defined(GD32_HAS_CAN0) | ||
144 | #error "GD32_HAS_CAN0 not defined in registry" | ||
145 | #endif | ||
146 | |||
147 | #if !defined(GD32_HAS_CAN1) | ||
148 | #error "GD32_HAS_CAN1 not defined in registry" | ||
149 | #endif | ||
150 | |||
151 | #if (GD32_HAS_CAN0 | GD32_HAS_CAN1) && !defined(GD32_CAN_MAX_FILTERS) | ||
152 | #error "GD32_CAN_MAX_FILTERS not defined in registry" | ||
153 | #endif | ||
154 | |||
155 | #if GD32_CAN_USE_CAN0 && !GD32_HAS_CAN0 | ||
156 | #error "CAN0 not present in the selected device" | ||
157 | #endif | ||
158 | |||
159 | #if GD32_CAN_USE_CAN1 && !GD32_HAS_CAN1 | ||
160 | #error "CAN1 not present in the selected device" | ||
161 | #endif | ||
162 | |||
163 | #if !GD32_CAN_USE_CAN0 && !GD32_CAN_USE_CAN1 | ||
164 | #error "CAN driver activated but no CAN peripheral assigned" | ||
165 | #endif | ||
166 | |||
167 | #if !GD32_CAN_USE_CAN0 && GD32_CAN_USE_CAN1 | ||
168 | #error "CAN1 requires CAN0, it cannot operate independently" | ||
169 | #endif | ||
170 | |||
171 | #if CAN_USE_SLEEP_MODE && !CAN_SUPPORTS_SLEEP | ||
172 | #error "CAN sleep mode not supported in this architecture" | ||
173 | #endif | ||
174 | |||
175 | /*===========================================================================*/ | ||
176 | /* Driver data structures and types. */ | ||
177 | /*===========================================================================*/ | ||
178 | |||
179 | /** | ||
180 | * @brief Type of a structure representing an CAN driver. | ||
181 | */ | ||
182 | typedef struct CANDriver CANDriver; | ||
183 | |||
184 | /** | ||
185 | * @brief Type of a transmission mailbox index. | ||
186 | */ | ||
187 | typedef uint32_t canmbx_t; | ||
188 | |||
189 | #if (CAN_ENFORCE_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) | ||
190 | /** | ||
191 | * @brief Type of a CAN notification callback. | ||
192 | * | ||
193 | * @param[in] canp pointer to the @p CANDriver object triggering the | ||
194 | * callback | ||
195 | * @param[in] flags flags associated to the mailbox callback | ||
196 | */ | ||
197 | typedef void (*can_callback_t)(CANDriver *canp, uint32_t flags); | ||
198 | #endif | ||
199 | |||
200 | /** | ||
201 | * @brief CAN transmission frame. | ||
202 | * @note Accessing the frame data as word16 or word32 is not portable because | ||
203 | * machine data endianness, it can be still useful for a quick filling. | ||
204 | */ | ||
205 | typedef struct { | ||
206 | struct { | ||
207 | uint8_t DLC:4; /**< @brief Data length. */ | ||
208 | uint8_t RTR:1; /**< @brief Frame type. */ | ||
209 | uint8_t IDE:1; /**< @brief Identifier type. */ | ||
210 | }; | ||
211 | union { | ||
212 | struct { | ||
213 | uint32_t SID:11; /**< @brief Standard identifier.*/ | ||
214 | }; | ||
215 | struct { | ||
216 | uint32_t EID:29; /**< @brief Extended identifier.*/ | ||
217 | }; | ||
218 | }; | ||
219 | union { | ||
220 | uint8_t data8[8]; /**< @brief Frame data. */ | ||
221 | uint16_t data16[4]; /**< @brief Frame data. */ | ||
222 | uint32_t data32[2]; /**< @brief Frame data. */ | ||
223 | uint64_t data64[1]; /**< @brief Frame data. */ | ||
224 | }; | ||
225 | } CANTxFrame; | ||
226 | |||
227 | /** | ||
228 | * @brief CAN received frame. | ||
229 | * @note Accessing the frame data as word16 or word32 is not portable because | ||
230 | * machine data endianness, it can be still useful for a quick filling. | ||
231 | */ | ||
232 | typedef struct { | ||
233 | struct { | ||
234 | uint8_t FMI; /**< @brief Filter id. */ | ||
235 | uint16_t TIME; /**< @brief Time stamp. */ | ||
236 | }; | ||
237 | struct { | ||
238 | uint8_t DLC:4; /**< @brief Data length. */ | ||
239 | uint8_t RTR:1; /**< @brief Frame type. */ | ||
240 | uint8_t IDE:1; /**< @brief Identifier type. */ | ||
241 | }; | ||
242 | union { | ||
243 | struct { | ||
244 | uint32_t SID:11; /**< @brief Standard identifier.*/ | ||
245 | }; | ||
246 | struct { | ||
247 | uint32_t EID:29; /**< @brief Extended identifier.*/ | ||
248 | }; | ||
249 | }; | ||
250 | union { | ||
251 | uint8_t data8[8]; /**< @brief Frame data. */ | ||
252 | uint16_t data16[4]; /**< @brief Frame data. */ | ||
253 | uint32_t data32[2]; /**< @brief Frame data. */ | ||
254 | uint64_t data64[1]; /**< @brief Frame data. */ | ||
255 | }; | ||
256 | } CANRxFrame; | ||
257 | |||
258 | /** | ||
259 | * @brief CAN filter. | ||
260 | * @note Refer to the GD32 reference manual for info about filters. | ||
261 | */ | ||
262 | typedef struct { | ||
263 | /** | ||
264 | * @brief Number of the filter bank to be programmed. | ||
265 | */ | ||
266 | uint32_t filter:16; | ||
267 | /** | ||
268 | * @brief Filter mode. | ||
269 | * @note This bit represent the CAN_FMCFG register bit associated to this | ||
270 | * filter (0=mask mode, 1=list mode). | ||
271 | */ | ||
272 | uint32_t mode:1; | ||
273 | /** | ||
274 | * @brief Filter scale. | ||
275 | * @note This bit represent the CAN_FSCFG register bit associated to this | ||
276 | * filter (0=16 bits mode, 1=32 bits mode). | ||
277 | */ | ||
278 | uint32_t scale:1; | ||
279 | /** | ||
280 | * @brief Filter mode. | ||
281 | * @note This bit represent the CAN_FAFIFO register bit associated to this | ||
282 | * filter, must be set to zero in this version of the driver. | ||
283 | */ | ||
284 | uint32_t assignment:1; | ||
285 | /** | ||
286 | * @brief Filter register 1 (identifier). | ||
287 | */ | ||
288 | uint32_t register1; | ||
289 | /** | ||
290 | * @brief Filter register 2 (mask/identifier depending on mode=0/1). | ||
291 | */ | ||
292 | uint32_t register2; | ||
293 | } CANFilter; | ||
294 | |||
295 | /** | ||
296 | * @brief Driver configuration structure. | ||
297 | */ | ||
298 | typedef struct { | ||
299 | /** | ||
300 | * @brief CAN CTL register initialization data. | ||
301 | * @note Some bits in this register are enforced by the driver regardless | ||
302 | * their status in this field. | ||
303 | */ | ||
304 | uint32_t ctl; | ||
305 | /** | ||
306 | * @brief CAN BT register initialization data. | ||
307 | * @note Some bits in this register are enforced by the driver regardless | ||
308 | * their status in this field. | ||
309 | */ | ||
310 | uint32_t bt; | ||
311 | } CANConfig; | ||
312 | |||
313 | /** | ||
314 | * @brief Structure representing an CAN driver. | ||
315 | */ | ||
316 | struct CANDriver { | ||
317 | /** | ||
318 | * @brief Driver state. | ||
319 | */ | ||
320 | canstate_t state; | ||
321 | /** | ||
322 | * @brief Current configuration data. | ||
323 | */ | ||
324 | const CANConfig *config; | ||
325 | /** | ||
326 | * @brief Transmission threads queue. | ||
327 | */ | ||
328 | threads_queue_t txqueue; | ||
329 | /** | ||
330 | * @brief Receive threads queue. | ||
331 | */ | ||
332 | threads_queue_t rxqueue; | ||
333 | #if (CAN_ENFORCE_USE_CALLBACKS == FALSE) || defined(__DOXYGEN__) | ||
334 | /** | ||
335 | * @brief One or more frames become available. | ||
336 | * @note After broadcasting this event it will not be broadcasted again | ||
337 | * until the received frames queue has been completely emptied. It | ||
338 | * is <b>not</b> broadcasted for each received frame. It is | ||
339 | * responsibility of the application to empty the queue by | ||
340 | * repeatedly invoking @p canReceive() when listening to this event. | ||
341 | * This behavior minimizes the interrupt served by the system | ||
342 | * because CAN traffic. | ||
343 | * @note The flags associated to the listeners will indicate which | ||
344 | * receive mailboxes become non-empty. | ||
345 | */ | ||
346 | event_source_t rxfull_event; | ||
347 | /** | ||
348 | * @brief One or more transmission mailbox become available. | ||
349 | * @note The flags associated to the listeners will indicate which | ||
350 | * transmit mailboxes become empty. | ||
351 | * @note The upper 16 bits are transmission error flags associated | ||
352 | * to the transmit mailboxes. | ||
353 | */ | ||
354 | event_source_t txempty_event; | ||
355 | /** | ||
356 | * @brief A CAN bus error happened. | ||
357 | * @note The flags associated to the listeners will indicate that | ||
358 | * receive error(s) have occurred. | ||
359 | * @note In this implementation the upper 16 bits are filled with the | ||
360 | * unprocessed content of the ESR register. | ||
361 | */ | ||
362 | event_source_t error_event; | ||
363 | #if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__) | ||
364 | /** | ||
365 | * @brief Entering sleep state event. | ||
366 | */ | ||
367 | event_source_t sleep_event; | ||
368 | /** | ||
369 | * @brief Exiting sleep state event. | ||
370 | */ | ||
371 | event_source_t wakeup_event; | ||
372 | #endif /* CAN_USE_SLEEP_MODE */ | ||
373 | #else /* CAN_ENFORCE_USE_CALLBACKS == TRUE */ | ||
374 | /** | ||
375 | * @brief One or more frames become available. | ||
376 | * @note After calling this function it will not be called again | ||
377 | * until the received frames queue has been completely emptied. It | ||
378 | * is <b>not</b> called for each received frame. It is | ||
379 | * responsibility of the application to empty the queue by | ||
380 | * repeatedly invoking @p chTryReceiveI(). | ||
381 | * This behavior minimizes the interrupt served by the system | ||
382 | * because CAN traffic. | ||
383 | */ | ||
384 | can_callback_t rxfull_cb; | ||
385 | /** | ||
386 | * @brief One or more transmission mailbox become available. | ||
387 | * @note The flags associated to the callback will indicate which | ||
388 | * transmit mailboxes become empty. | ||
389 | */ | ||
390 | can_callback_t txempty_cb; | ||
391 | /** | ||
392 | * @brief A CAN bus error happened. | ||
393 | */ | ||
394 | can_callback_t error_cb; | ||
395 | #if (CAN_USE_SLEEP_MODE == TRUE) || defined (__DOXYGEN__) | ||
396 | /** | ||
397 | * @brief Exiting sleep state. | ||
398 | */ | ||
399 | can_callback_t wakeup_cb; | ||
400 | #endif | ||
401 | #endif | ||
402 | /* End of the mandatory fields.*/ | ||
403 | /** | ||
404 | * @brief Pointer to the CAN registers. | ||
405 | */ | ||
406 | CAN_TypeDef *can; | ||
407 | }; | ||
408 | |||
409 | /*===========================================================================*/ | ||
410 | /* Driver macros. */ | ||
411 | /*===========================================================================*/ | ||
412 | |||
413 | /*===========================================================================*/ | ||
414 | /* External declarations. */ | ||
415 | /*===========================================================================*/ | ||
416 | |||
417 | #if GD32_CAN_USE_CAN0 && !defined(__DOXYGEN__) | ||
418 | extern CANDriver CAND1; | ||
419 | #endif | ||
420 | |||
421 | #if GD32_CAN_USE_CAN1 && !defined(__DOXYGEN__) | ||
422 | extern CANDriver CAND2; | ||
423 | #endif | ||
424 | |||
425 | #ifdef __cplusplus | ||
426 | extern "C" { | ||
427 | #endif | ||
428 | void can_lld_init(void); | ||
429 | void can_lld_start(CANDriver *canp); | ||
430 | void can_lld_stop(CANDriver *canp); | ||
431 | bool can_lld_is_tx_empty(CANDriver *canp, canmbx_t mailbox); | ||
432 | void can_lld_transmit(CANDriver *canp, | ||
433 | canmbx_t mailbox, | ||
434 | const CANTxFrame *crfp); | ||
435 | bool can_lld_is_rx_nonempty(CANDriver *canp, canmbx_t mailbox); | ||
436 | void can_lld_receive(CANDriver *canp, | ||
437 | canmbx_t mailbox, | ||
438 | CANRxFrame *ctfp); | ||
439 | void can_lld_abort(CANDriver *canp, | ||
440 | canmbx_t mailbox); | ||
441 | #if CAN_USE_SLEEP_MODE | ||
442 | void can_lld_sleep(CANDriver *canp); | ||
443 | void can_lld_wakeup(CANDriver *canp); | ||
444 | #endif /* CAN_USE_SLEEP_MODE */ | ||
445 | void canGD32SetFilters(CANDriver *canp, uint32_t can2sb, | ||
446 | uint32_t num, const CANFilter *cfp); | ||
447 | #ifdef __cplusplus | ||
448 | } | ||
449 | #endif | ||
450 | |||
451 | #endif /* HAL_USE_CAN */ | ||
452 | |||
453 | #endif /* HAL_CAN_LLD_H */ | ||
454 | |||
455 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/driver.mk b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/driver.mk new file mode 100644 index 000000000..48a731550 --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/driver.mk | |||
@@ -0,0 +1,11 @@ | |||
1 | ifeq ($(USE_SMART_BUILD),yes) | ||
2 | ifneq ($(findstring HAL_USE_CRC TRUE,$(HALCONF)),) | ||
3 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.c \ | ||
4 | ${CHIBIOS_CONTRIB}/os/various/crcsw.c | ||
5 | endif | ||
6 | else | ||
7 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.c \ | ||
8 | ${CHIBIOS_CONTRIB}/os/various/crcsw.c | ||
9 | endif | ||
10 | |||
11 | PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/CRC | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.c b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.c new file mode 100755 index 000000000..8ea3d8e9d --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.c | |||
@@ -0,0 +1,259 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2015 Michael D. Spradling | ||
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/CRC/hal_crc_lld.c | ||
20 | * @brief GD32 CRC subsystem low level driver source. | ||
21 | * | ||
22 | * @addtogroup CRC | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #include "hal.h" | ||
27 | |||
28 | #if (HAL_USE_CRC == TRUE) || defined(__DOXYGEN__) | ||
29 | /** | ||
30 | * Allow CRC Software override for ST drivers. Some ST CRC implimentations | ||
31 | * have limited capabilities. | ||
32 | */ | ||
33 | #if CRCSW_USE_CRC1 != TRUE | ||
34 | /*===========================================================================*/ | ||
35 | /* Driver local definitions. */ | ||
36 | /*===========================================================================*/ | ||
37 | |||
38 | /** | ||
39 | * @brief CRC default configuration. | ||
40 | */ | ||
41 | static const CRCConfig default_config = { | ||
42 | .poly_size = 32, | ||
43 | .poly = 0x04C11DB7, | ||
44 | .initial_val = 0xFFFFFFFF, | ||
45 | .final_val = 0xFFFFFFFF, | ||
46 | .reflect_data = 1, | ||
47 | .reflect_remainder = 1 | ||
48 | }; | ||
49 | |||
50 | /*===========================================================================*/ | ||
51 | /* Driver exported variables. */ | ||
52 | /*===========================================================================*/ | ||
53 | |||
54 | /** @brief CRC1 driver identifier.*/ | ||
55 | #if GD32_CRC_USE_CRC0 || defined(__DOXYGEN__) | ||
56 | CRCDriver CRCD1; | ||
57 | #endif | ||
58 | |||
59 | /*===========================================================================*/ | ||
60 | /* Driver local variables and types. */ | ||
61 | /*===========================================================================*/ | ||
62 | |||
63 | /*===========================================================================*/ | ||
64 | /* Driver local functions. */ | ||
65 | /*===========================================================================*/ | ||
66 | |||
67 | void _crc_lld_calc_byte(CRCDriver *crcp, uint8_t data) { | ||
68 | __IO uint8_t *crc8 = (__IO uint8_t*)&(crcp->crc->DATA); | ||
69 | *crc8 = data; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * @brief Returns calculated CRC from last reset | ||
74 | * | ||
75 | * @param[in] crcp pointer to the @p CRCDriver object | ||
76 | * @param[in] data data to be added to crc | ||
77 | * | ||
78 | * @notapi | ||
79 | */ | ||
80 | void _crc_lld_calc_halfword(CRCDriver *crcp, uint16_t data) { | ||
81 | __IO uint16_t *crc16 = (__IO uint16_t*)&(crcp->crc->DATA); | ||
82 | *crc16 = data; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * @brief Returns calculated CRC from last reset | ||
87 | * | ||
88 | * @param[in] crcp pointer to the @p CRCDriver object | ||
89 | * @param[in] data data to be added to crc | ||
90 | * | ||
91 | * @notapi | ||
92 | */ | ||
93 | void _crc_lld_calc_word(CRCDriver *crcp, uint32_t data) { | ||
94 | crcp->crc->DATA = data; | ||
95 | } | ||
96 | |||
97 | |||
98 | /*===========================================================================*/ | ||
99 | /* Driver interrupt handlers. */ | ||
100 | /*===========================================================================*/ | ||
101 | |||
102 | /** | ||
103 | * @brief Shared end-of-rx service routine. | ||
104 | * | ||
105 | * @param[in] crcp pointer to the @p CRCDriver object | ||
106 | * @param[in] flags pre-shifted content of the ISR register | ||
107 | */ | ||
108 | #if CRC_USE_DMA == TRUE | ||
109 | static void crc_lld_serve_interrupt(CRCDriver *crcp, uint32_t flags) { | ||
110 | |||
111 | /* DMA errors handling.*/ | ||
112 | #if defined(GD32_CRC_DMA_ERROR_HOOK) | ||
113 | if ((flags & (GD32_DMA_INTF_ERRIF)) != 0) { | ||
114 | GD32_CRC_DMA_ERROR_HOOK(crcp); | ||
115 | } | ||
116 | #else | ||
117 | (void)flags; | ||
118 | #endif | ||
119 | |||
120 | /* Stop everything.*/ | ||
121 | dmaStreamDisable(crcp->dmastp); | ||
122 | |||
123 | if (crcp->rem_data_size) { | ||
124 | /* Start DMA follow up transfer for next data chunk */ | ||
125 | crc_lld_start_calc(crcp, crcp->rem_data_size, | ||
126 | (const void *)crcp->dmastp->channel->PADDR+0xffff); | ||
127 | } else { | ||
128 | /* Portable CRC ISR code defined in the high level driver, note, it is a macro.*/ | ||
129 | _crc_isr_code(crcp, crcp->crc->DATA ^ crcp->config->final_val); | ||
130 | } | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | /*===========================================================================*/ | ||
135 | /* Driver exported functions. */ | ||
136 | /*===========================================================================*/ | ||
137 | |||
138 | /** | ||
139 | * @brief Low level CRC driver initialization. | ||
140 | * | ||
141 | * @notapi | ||
142 | */ | ||
143 | void crc_lld_init(void) { | ||
144 | crcObjectInit(&CRCD1); | ||
145 | CRCD1.crc = CRC; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * @brief Configures and activates the CRC peripheral. | ||
150 | * | ||
151 | * @param[in] crcp pointer to the @p CRCDriver object | ||
152 | * | ||
153 | * @notapi | ||
154 | */ | ||
155 | void crc_lld_start(CRCDriver *crcp) { | ||
156 | if (crcp->config == NULL) | ||
157 | crcp->config = &default_config; | ||
158 | |||
159 | rcuEnableCRC( FALSE ); | ||
160 | |||
161 | osalDbgAssert(crcp->config->initial_val == default_config.initial_val, | ||
162 | "hardware doesn't support programmable initial value"); | ||
163 | osalDbgAssert(crcp->config->poly_size == default_config.poly_size, | ||
164 | "hardware doesn't support programmable polynomial size"); | ||
165 | osalDbgAssert(crcp->config->poly == default_config.poly, | ||
166 | "hardware doesn't support programmable polynomial"); | ||
167 | osalDbgAssert(crcp->config->reflect_data == default_config.reflect_data, | ||
168 | "hardware doesn't support reflect of input data"); | ||
169 | osalDbgAssert(crcp->config->reflect_remainder == default_config.reflect_remainder, | ||
170 | "hardware doesn't support reflect of output remainder"); | ||
171 | |||
172 | #if CRC_USE_DMA == TRUE | ||
173 | crcp->dmamode = GD32_DMA_CTL_DIR_M2M | GD32_DMA_CTL_PNAGA | | ||
174 | GD32_DMA_CTL_MWIDTH_WORD | GD32_DMA_CTL_PWIDTH_WORD | | ||
175 | GD32_DMA_CTL_ERRIE | GD32_DMA_CTL_FTFIE | | ||
176 | GD32_DMA_CTL_PRIO(GD32_CRC_CRC0_DMA_PRIORITY); | ||
177 | { | ||
178 | crcp->dmastp = dmaStreamAlloc(GD32_CRC_CRC0_DMA_STREAM, | ||
179 | GD32_CRC_CRC0_DMA_IRQ_PRIORITY, | ||
180 | (gd32_dmaisr_t)crc_lld_serve_interrupt, | ||
181 | (void *)crcp); | ||
182 | osalDbgAssert(crcp->dmastp != NULL, "unable to allocate stream"); | ||
183 | } | ||
184 | #endif | ||
185 | } | ||
186 | |||
187 | |||
188 | /** | ||
189 | * @brief Deactivates the CRC peripheral. | ||
190 | * | ||
191 | * @param[in] crcp pointer to the @p CRCDriver object | ||
192 | * | ||
193 | * @notapi | ||
194 | */ | ||
195 | void crc_lld_stop(CRCDriver *crcp) { | ||
196 | #if CRC_USE_DMA == TRUE | ||
197 | dmaStreamFree(crcp->dmastp); | ||
198 | #else | ||
199 | (void)crcp; | ||
200 | #endif | ||
201 | rcuDisableCRC(); | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * @brief Resets current CRC calculation. | ||
206 | * | ||
207 | * @param[in] crcp pointer to the @p CRCDriver object | ||
208 | * | ||
209 | * @notapi | ||
210 | */ | ||
211 | void crc_lld_reset(CRCDriver *crcp) { | ||
212 | crcp->crc->CTL |= CRC_CTL_RST; | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * @brief Returns calculated CRC from last reset | ||
217 | * | ||
218 | * @param[in] crcp pointer to the @p CRCDriver object | ||
219 | * @param[in] n size of buf in bytes | ||
220 | * @param[in] buf @p buffer location | ||
221 | * | ||
222 | * @notapi | ||
223 | */ | ||
224 | uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf) { | ||
225 | #if CRC_USE_DMA == TRUE | ||
226 | crc_lld_start_calc(crcp, n, buf); | ||
227 | (void) osalThreadSuspendS(&crcp->thread); | ||
228 | #else | ||
229 | while(n > 3) { | ||
230 | _crc_lld_calc_word(crcp, *(uint32_t*)buf); | ||
231 | buf+=4; | ||
232 | n-=4; | ||
233 | } | ||
234 | osalDbgAssert(n == 0, "GD32 CRC Unit only supports WORD accesses"); | ||
235 | #endif | ||
236 | return crcp->crc->DATA ^ crcp->config->final_val; | ||
237 | } | ||
238 | |||
239 | #if CRC_USE_DMA == TRUE | ||
240 | void crc_lld_start_calc(CRCDriver *crcp, size_t n, const void *buf) { | ||
241 | /* The GD32 DMA can only handle max 65535 bytes per transfer | ||
242 | * because it's data count register has only 16 bit. */ | ||
243 | size_t sz = (n > 0xffff) ? 0xffff : n; | ||
244 | crcp->rem_data_size = n-sz; | ||
245 | |||
246 | dmaStreamSetPeripheral(crcp->dmastp, buf); | ||
247 | dmaStreamSetMemory0(crcp->dmastp, &crcp->crc->DATA); | ||
248 | dmaStreamSetTransactionSize(crcp->dmastp, (sz / 4)); | ||
249 | dmaStreamSetMode(crcp->dmastp, crcp->dmamode); | ||
250 | |||
251 | dmaStreamEnable(crcp->dmastp); | ||
252 | } | ||
253 | #endif | ||
254 | |||
255 | #endif /* CRCSW_USE_CRC1 */ | ||
256 | |||
257 | #endif /* HAL_USE_CRC */ | ||
258 | |||
259 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.h b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.h new file mode 100644 index 000000000..926bdb62b --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/CRC/hal_crc_lld.h | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2015 Michael D. Spradling | ||
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/CRC/hal_crc_lld.h | ||
20 | * @brief GD CRC subsystem low level driver header. | ||
21 | * | ||
22 | * @addtogroup CRC | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #ifndef HAL_CRC_LLD_H_ | ||
27 | #define HAL_CRC_LLD_H_ | ||
28 | |||
29 | #if (HAL_USE_CRC == TRUE) || defined(__DOXYGEN__) | ||
30 | /* | ||
31 | * This error check must occur outsite of CRCSW_USE_CRC1 to check if | ||
32 | * two LLD drivers are enabled at the same time | ||
33 | */ | ||
34 | #if GD32_CRC_USE_CRC0 == TRUE && \ | ||
35 | CRCSW_USE_CRC1 == TRUE | ||
36 | #error "Software CRC can't be enable with GD32_CRC_USE_CRC0" | ||
37 | #endif | ||
38 | |||
39 | /** | ||
40 | * Allow CRC Software override for ST drivers. Some ST CRC implimentations | ||
41 | * have limited capabilities. | ||
42 | */ | ||
43 | #if CRCSW_USE_CRC1 != TRUE | ||
44 | |||
45 | /*===========================================================================*/ | ||
46 | /* Driver constants. */ | ||
47 | /*===========================================================================*/ | ||
48 | |||
49 | /*===========================================================================*/ | ||
50 | /* Driver pre-compile time settings. */ | ||
51 | /*===========================================================================*/ | ||
52 | |||
53 | /** | ||
54 | * @name Configuration options | ||
55 | * @{ | ||
56 | */ | ||
57 | /** | ||
58 | * @brief CRC0 driver enable switch. | ||
59 | * @details If set to @p TRUE the support for CRC1 is included. | ||
60 | * @note The default is @p FALSE. | ||
61 | */ | ||
62 | #if !defined(GD32_CRC_USE_CRC0) || defined(__DOXYGEN__) | ||
63 | #define GD32_CRC_USE_CRC0 FALSE | ||
64 | #endif | ||
65 | |||
66 | /** | ||
67 | * @brief CRC0 DMA priority (0..3|lowest..highest). | ||
68 | * @note The priority level is for CRC DMA stream. | ||
69 | */ | ||
70 | #if !defined(GD32_CRC_CRC0_DMA_PRIORITY) || defined(__DOXYGEN__) | ||
71 | #define GD32_CRC_CRC0_DMA_PRIORITY 2 | ||
72 | #endif | ||
73 | |||
74 | /** | ||
75 | * @brief CRC0 DMA interrupt priority level setting. | ||
76 | */ | ||
77 | #if !defined(GD32_CRC_CRC0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) | ||
78 | #define GD32_CRC_CRC0_DMA_IRQ_PRIORITY 14 | ||
79 | #endif | ||
80 | |||
81 | /** | ||
82 | * @brief CRC0 DMA STREAM to use when performing CRC calculation. | ||
83 | */ | ||
84 | #if !defined(GD32_CRC_CRC0_DMA_STREAM) || defined(__DOXYGEN__) | ||
85 | #define GD32_CRC_CRC0_DMA_STREAM GD32_DMA_STREAM_ID(0, 1) | ||
86 | #endif | ||
87 | |||
88 | /** | ||
89 | * @brief CRC DMA error hook. | ||
90 | */ | ||
91 | #if !defined(GD32_CRC_DMA_ERROR_HOOK) || defined(__DOXYGEN__) | ||
92 | #define GD32_CRC_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") | ||
93 | #endif | ||
94 | |||
95 | /*===========================================================================*/ | ||
96 | /* Derived constants and error checks. */ | ||
97 | /*===========================================================================*/ | ||
98 | |||
99 | #if GD32_CRC_USE_CRC0 && !GD32_HAS_CRC | ||
100 | #error "Hardware CRC not present in the selected device" | ||
101 | #error "Use CRCSW_USE_CRC1 for software implementation" | ||
102 | #endif | ||
103 | |||
104 | #if CRC_USE_DMA | ||
105 | #if GD32_CRC_USE_CRC0 && \ | ||
106 | !OSAL_IRQ_IS_VALID_PRIORITY(GD32_CRC_CRC0_DMA_IRQ_PRIORITY) | ||
107 | #error "Invalid IRQ priority assigned to CRC0" | ||
108 | #endif | ||
109 | |||
110 | #if GD32_CRC_USE_CRC0 && \ | ||
111 | !GD32_DMA_IS_VALID_PRIORITY(GD32_CRC_CRC0_DMA_PRIORITY) | ||
112 | #error "Invalid DMA priority assigned to CRC0" | ||
113 | #endif | ||
114 | |||
115 | #if !defined(GD32_DMA_REQUIRED) | ||
116 | #define GD32_DMA_REQUIRED | ||
117 | #endif | ||
118 | #endif | ||
119 | |||
120 | /*===========================================================================*/ | ||
121 | /* Driver data structures and types. */ | ||
122 | /*===========================================================================*/ | ||
123 | |||
124 | /** | ||
125 | * @brief Type of a structure representing an CRC driver. | ||
126 | */ | ||
127 | typedef struct CRCDriver CRCDriver; | ||
128 | |||
129 | /** | ||
130 | * @brief CRC notification callback type | ||
131 | * | ||
132 | * @param[in] crcp pointer to the @ CRCDriver object triggering the | ||
133 | * callback | ||
134 | */ | ||
135 | typedef void (*crccallback_t)(CRCDriver *crcp, uint32_t crc); | ||
136 | |||
137 | /** | ||
138 | * @brief Driver configuration structure. | ||
139 | */ | ||
140 | typedef struct { | ||
141 | /** | ||
142 | * @brief The size of polynomial to be used for CRC. | ||
143 | */ | ||
144 | uint32_t poly_size; | ||
145 | /** | ||
146 | * @brief The coefficients of the polynomial to be used for CRC. | ||
147 | */ | ||
148 | uint32_t poly; | ||
149 | /** | ||
150 | * @brief The inital value | ||
151 | */ | ||
152 | uint32_t initial_val; | ||
153 | /** | ||
154 | * @brief The final XOR value | ||
155 | */ | ||
156 | uint32_t final_val; | ||
157 | /** | ||
158 | * @brief Reflect bit order data going into CRC | ||
159 | */ | ||
160 | bool reflect_data; | ||
161 | /** | ||
162 | * @brief Reflect bit order of final remainder | ||
163 | */ | ||
164 | bool reflect_remainder; | ||
165 | /* End of the mandatory fields.*/ | ||
166 | /** | ||
167 | * @brief Operation complete callback or @p NULL | ||
168 | */ | ||
169 | crccallback_t end_cb; | ||
170 | } CRCConfig; | ||
171 | |||
172 | |||
173 | /** | ||
174 | * @brief Structure representing an CRC driver. | ||
175 | */ | ||
176 | struct CRCDriver { | ||
177 | /** | ||
178 | * @brief Driver state. | ||
179 | */ | ||
180 | crcstate_t state; | ||
181 | /** | ||
182 | * @brief Current configuration data. | ||
183 | */ | ||
184 | const CRCConfig *config; | ||
185 | #if CRC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) | ||
186 | /** | ||
187 | * @brief Mutex protecting the peripheral. | ||
188 | */ | ||
189 | mutex_t mutex; | ||
190 | #endif /* CRC_USE_MUTUAL_EXCLUSION */ | ||
191 | #if defined(CRC_DRIVER_EXT_FIELDS) | ||
192 | CRC_DRIVER_EXT_FIELDS | ||
193 | #endif | ||
194 | /* End of the mandatory fields.*/ | ||
195 | /** | ||
196 | * @brief Pointer to the CRCx registers block. | ||
197 | */ | ||
198 | CRC_TypeDef *crc; | ||
199 | |||
200 | #if CRC_USE_DMA == TRUE | ||
201 | /** | ||
202 | * @brief Waiting thread. | ||
203 | */ | ||
204 | thread_reference_t thread; | ||
205 | /** | ||
206 | * @brief Remaining data size. | ||
207 | * @note The DMA can handle only 65535 bytes per transfer because | ||
208 | * it's data count register is only 16 bits wide. | ||
209 | */ | ||
210 | size_t rem_data_size; | ||
211 | /** | ||
212 | * @brief CRC DMA stream | ||
213 | */ | ||
214 | const gd32_dma_stream_t *dmastp; | ||
215 | /** | ||
216 | * @brief DMA mode bit mask. | ||
217 | */ | ||
218 | uint32_t dmamode; | ||
219 | #endif | ||
220 | }; | ||
221 | |||
222 | /*===========================================================================*/ | ||
223 | /* Driver macros. */ | ||
224 | /*===========================================================================*/ | ||
225 | |||
226 | /*===========================================================================*/ | ||
227 | /* External declarations. */ | ||
228 | /*===========================================================================*/ | ||
229 | |||
230 | #if GD32_CRC_USE_CRC0 && !defined(__DOXYGEN__) | ||
231 | extern CRCDriver CRCD1; | ||
232 | #endif /* GD32_CRC_USE_CRC0 */ | ||
233 | |||
234 | #ifdef __cplusplus | ||
235 | extern "C" { | ||
236 | #endif | ||
237 | void crc_lld_init(void); | ||
238 | void crc_lld_start(CRCDriver *crcp); | ||
239 | void crc_lld_stop(CRCDriver *crcp); | ||
240 | void crc_lld_reset(CRCDriver *crcp); | ||
241 | uint32_t crc_lld_calc(CRCDriver *crcp, size_t n, const void *buf); | ||
242 | #if CRC_USE_DMA | ||
243 | void crc_lld_start_calc(CRCDriver *crcp, size_t n, const void *buf); | ||
244 | #endif | ||
245 | #ifdef __cplusplus | ||
246 | } | ||
247 | #endif | ||
248 | |||
249 | #endif /* CRCSW_USE_CRC1 */ | ||
250 | |||
251 | #endif /* HAL_USE_CRC */ | ||
252 | |||
253 | #endif /* HAL_CRC_LLD_H_ */ | ||
254 | |||
255 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/driver.mk b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/driver.mk new file mode 100644 index 000000000..1f2a501fa --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/driver.mk | |||
@@ -0,0 +1,9 @@ | |||
1 | ifeq ($(USE_SMART_BUILD),yes) | ||
2 | ifneq ($(findstring HAL_USE_DAC TRUE,$(HALCONF)),) | ||
3 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.c | ||
4 | endif | ||
5 | else | ||
6 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.c | ||
7 | endif | ||
8 | |||
9 | PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/DAC | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.c b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.c new file mode 100644 index 000000000..baeecbda3 --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.c | |||
@@ -0,0 +1,462 @@ | |||
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 DAC/hal_dac_lld.c | ||
20 | * @brief GD32 DAC subsystem low level driver source. | ||
21 | * | ||
22 | * @addtogroup DAC | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #include "hal.h" | ||
27 | |||
28 | #if HAL_USE_DAC || defined(__DOXYGEN__) | ||
29 | |||
30 | /*===========================================================================*/ | ||
31 | /* Driver local definitions. */ | ||
32 | /*===========================================================================*/ | ||
33 | |||
34 | #define DAC_CH1_DMA_CHANNEL \ | ||
35 | GD32_DMA_GETCHANNEL(GD32_DAC_CH1_DMA_STREAM, \ | ||
36 | GD32_DAC_CH1_DMA_CHN) | ||
37 | |||
38 | #define DAC_CH2_DMA_CHANNEL \ | ||
39 | GD32_DMA_GETCHANNEL(GD32_DAC_CH2_DMA_STREAM, \ | ||
40 | GD32_DAC_CH2_DMA_CHN) | ||
41 | |||
42 | #define CHANNEL_DATA_OFFSET 3U | ||
43 | |||
44 | /*===========================================================================*/ | ||
45 | /* Driver exported variables. */ | ||
46 | /*===========================================================================*/ | ||
47 | |||
48 | /** @brief DAC CH1 driver identifier.*/ | ||
49 | #if GD32_DAC_USE_DAC_CH1 || defined(__DOXYGEN__) | ||
50 | DACDriver DACD1; | ||
51 | #endif | ||
52 | |||
53 | /** @brief DAC CH2 driver identifier.*/ | ||
54 | #if (GD32_DAC_USE_DAC_CH2 && !GD32_DAC_DUAL_MODE) || defined(__DOXYGEN__) | ||
55 | DACDriver DACD2; | ||
56 | #endif | ||
57 | |||
58 | /*===========================================================================*/ | ||
59 | /* Driver local variables. */ | ||
60 | /*===========================================================================*/ | ||
61 | |||
62 | #if GD32_DAC_USE_DAC_CH1 == TRUE | ||
63 | static const dacparams_t dac1_ch1_params = { | ||
64 | .dac = DAC, | ||
65 | .dataoffset = 0U, | ||
66 | .regshift = 0U, | ||
67 | .regmask = 0xFFFF0000U, | ||
68 | .dmastream = GD32_DAC_CH1_DMA_STREAM, | ||
69 | .dmamode = GD32_DMA_CTL_CHSEL(DAC_CH1_DMA_CHANNEL) | | ||
70 | GD32_DMA_CTL_PRIO(GD32_DAC_CH1_DMA_PRIORITY) | | ||
71 | GD32_DMA_CTL_MNAGA | GD32_DMA_CTL_CMEN | GD32_DMA_CTL_DIR_M2P | | ||
72 | GD32_DMA_CTL_ERRIE | GD32_DMA_CTL_HTFIE | | ||
73 | GD32_DMA_CTL_FTFIE, | ||
74 | .dmairqprio = GD32_DAC_CH1_IRQ_PRIORITY | ||
75 | }; | ||
76 | #endif | ||
77 | |||
78 | #if GD32_DAC_USE_DAC_CH2 == TRUE | ||
79 | static const dacparams_t dac1_ch2_params = { | ||
80 | .dac = DAC, | ||
81 | .dataoffset = CHANNEL_DATA_OFFSET, | ||
82 | .regshift = 16U, | ||
83 | .regmask = 0x0000FFFFU, | ||
84 | .dmastream = GD32_DAC_CH2_DMA_STREAM, | ||
85 | .dmamode = GD32_DMA_CTL_CHSEL(DAC_CH2_DMA_CHANNEL) | | ||
86 | GD32_DMA_CTL_PRIO(GD32_DAC_CH2_DMA_PRIORITY) | | ||
87 | GD32_DMA_CTL_MNAGA | GD32_DMA_CTL_CMEN | GD32_DMA_CTL_DIR_M2P | | ||
88 | GD32_DMA_CTL_ERRIE | GD32_DMA_CTL_HTFIE | | ||
89 | GD32_DMA_CTL_FTFIE, | ||
90 | .dmairqprio = GD32_DAC_CH2_IRQ_PRIORITY | ||
91 | }; | ||
92 | #endif | ||
93 | |||
94 | /*===========================================================================*/ | ||
95 | /* Driver local functions. */ | ||
96 | /*===========================================================================*/ | ||
97 | |||
98 | /** | ||
99 | * @brief Shared end/half-of-tx service routine. | ||
100 | * | ||
101 | * @param[in] dacp pointer to the @p DACDriver object | ||
102 | * @param[in] flags pre-shifted content of the ISR register | ||
103 | */ | ||
104 | static void dac_lld_serve_tx_interrupt(DACDriver *dacp, uint32_t flags) { | ||
105 | |||
106 | if ((flags & (GD32_DMA_INTF_ERRIF)) != 0) { | ||
107 | /* DMA errors handling.*/ | ||
108 | dac_lld_stop_conversion(dacp); | ||
109 | _dac_isr_error_code(dacp, DAC_ERR_DMAFAILURE); | ||
110 | } | ||
111 | else { | ||
112 | if ((flags & GD32_DMA_INTF_HTFIF) != 0) { | ||
113 | /* Half transfer processing.*/ | ||
114 | _dac_isr_half_code(dacp); | ||
115 | } | ||
116 | if ((flags & GD32_DMA_INTF_FTFIF) != 0) { | ||
117 | /* Transfer complete processing.*/ | ||
118 | _dac_isr_full_code(dacp); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | /*===========================================================================*/ | ||
124 | /* Driver interrupt handlers. */ | ||
125 | /*===========================================================================*/ | ||
126 | |||
127 | /*===========================================================================*/ | ||
128 | /* Driver exported functions. */ | ||
129 | /*===========================================================================*/ | ||
130 | |||
131 | /** | ||
132 | * @brief Low level DAC driver initialization. | ||
133 | * | ||
134 | * @notapi | ||
135 | */ | ||
136 | void dac_lld_init(void) { | ||
137 | |||
138 | #if GD32_DAC_USE_DAC_CH1 | ||
139 | dacObjectInit(&DACD1); | ||
140 | DACD1.params = &dac1_ch1_params; | ||
141 | DACD1.dma = NULL; | ||
142 | #endif | ||
143 | |||
144 | #if GD32_DAC_USE_DAC_CH2 | ||
145 | dacObjectInit(&DACD2); | ||
146 | DACD2.params = &dac1_ch2_params; | ||
147 | DACD2.dma = NULL; | ||
148 | #endif | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * @brief Configures and activates the DAC peripheral. | ||
153 | * | ||
154 | * @param[in] dacp pointer to the @p DACDriver object | ||
155 | * | ||
156 | * @notapi | ||
157 | */ | ||
158 | void dac_lld_start(DACDriver *dacp) { | ||
159 | |||
160 | /* If the driver is in DAC_STOP state then a full initialization is | ||
161 | required.*/ | ||
162 | if (dacp->state == DAC_STOP) { | ||
163 | dacchannel_t channel = 0; | ||
164 | |||
165 | /* Enabling the clock source.*/ | ||
166 | #if GD32_DAC_USE_DAC_CH1 | ||
167 | if (&DACD1 == dacp) { | ||
168 | rcuEnableDAC(true); | ||
169 | } | ||
170 | #endif | ||
171 | |||
172 | #if GD32_DAC_USE_DAC_CH2 | ||
173 | if (&DACD2 == dacp) { | ||
174 | rcuEnableDAC(true); | ||
175 | channel = 1; | ||
176 | } | ||
177 | #endif | ||
178 | |||
179 | /* Enabling DAC in SW triggering mode initially, initializing data to | ||
180 | zero.*/ | ||
181 | #if GD32_DAC_DUAL_MODE == FALSE | ||
182 | { | ||
183 | uint32_t ctl; | ||
184 | |||
185 | ctl = dacp->params->dac->CTL; | ||
186 | ctl &= dacp->params->regmask; | ||
187 | ctl |= (DAC_CTL_DEN0 | dacp->config->ctl) << dacp->params->regshift; | ||
188 | dacp->params->dac->CTL = ctl; | ||
189 | dac_lld_put_channel(dacp, channel, dacp->config->init); | ||
190 | } | ||
191 | #else | ||
192 | if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) || | ||
193 | (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) || | ||
194 | (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) { | ||
195 | dacp->params->dac->CTL = DAC_CTL_DEN1 | (dacp->config->ctl << 16) | DAC_CTL_DEN0 | dacp->config->ctl; | ||
196 | dac_lld_put_channel(dacp, 1U, dacp->config->init); | ||
197 | } | ||
198 | else { | ||
199 | dacp->params->dac->CTL = DAC_CTL_DEN0 | dacp->config->ctl; | ||
200 | } | ||
201 | dac_lld_put_channel(dacp, channel, dacp->config->init); | ||
202 | #endif | ||
203 | } | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * @brief Deactivates the DAC peripheral. | ||
208 | * | ||
209 | * @param[in] dacp pointer to the @p DACDriver object | ||
210 | * | ||
211 | * @notapi | ||
212 | */ | ||
213 | void dac_lld_stop(DACDriver *dacp) { | ||
214 | |||
215 | /* If in ready state then disables the DAC clock.*/ | ||
216 | if (dacp->state == DAC_READY) { | ||
217 | |||
218 | /* Disabling DAC.*/ | ||
219 | dacp->params->dac->CTL &= dacp->params->regmask; | ||
220 | |||
221 | #if GD32_DAC_USE_DAC_CH1 | ||
222 | if (&DACD1 == dacp) { | ||
223 | if ((dacp->params->dac->CTL & DAC_CTL_DEN1) == 0U) { | ||
224 | rcuDisableDAC(); | ||
225 | } | ||
226 | } | ||
227 | #endif | ||
228 | |||
229 | #if GD32_DAC_USE_DAC_CH2 | ||
230 | if (&DACD2 == dacp) { | ||
231 | if ((dacp->params->dac->CTL & DAC_CTL_DEN0) == 0U) { | ||
232 | rcuDisableDAC(); | ||
233 | } | ||
234 | } | ||
235 | #endif | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * @brief Outputs a value directly on a DAC channel. | ||
241 | * | ||
242 | * @param[in] dacp pointer to the @p DACDriver object | ||
243 | * @param[in] channel DAC channel number | ||
244 | * @param[in] sample value to be output | ||
245 | * | ||
246 | * @api | ||
247 | */ | ||
248 | void dac_lld_put_channel(DACDriver *dacp, | ||
249 | dacchannel_t channel, | ||
250 | dacsample_t sample) { | ||
251 | |||
252 | switch (dacp->config->datamode) { | ||
253 | case DAC_DHRM_12BIT_RIGHT: | ||
254 | #if GD32_DAC_DUAL_MODE | ||
255 | case DAC_DHRM_12BIT_RIGHT_DUAL: | ||
256 | #endif | ||
257 | if (channel == 0U) { | ||
258 | #if GD32_DAC_DUAL_MODE | ||
259 | dacp->params->dac->R12DH0 = (uint32_t)sample; | ||
260 | #else | ||
261 | *(&dacp->params->dac->R12DH0 + dacp->params->dataoffset) = (uint32_t)sample; | ||
262 | #endif | ||
263 | } | ||
264 | #if (GD32_HAS_DAC_CH2) | ||
265 | else { | ||
266 | dacp->params->dac->R12DH1 = (uint32_t)sample; | ||
267 | } | ||
268 | #endif | ||
269 | break; | ||
270 | case DAC_DHRM_12BIT_LEFT: | ||
271 | #if GD32_DAC_DUAL_MODE | ||
272 | case DAC_DHRM_12BIT_LEFT_DUAL: | ||
273 | #endif | ||
274 | if (channel == 0U) { | ||
275 | #if GD32_DAC_DUAL_MODE | ||
276 | dacp->params->dac->L12DH0 = (uint32_t)sample; | ||
277 | #else | ||
278 | *(&dacp->params->dac->L12DH0 + dacp->params->dataoffset) = (uint32_t)sample; | ||
279 | #endif | ||
280 | } | ||
281 | #if (GD32_HAS_DAC_CH2) | ||
282 | else { | ||
283 | dacp->params->dac->L12DH1 = (uint32_t)sample; | ||
284 | } | ||
285 | #endif | ||
286 | break; | ||
287 | case DAC_DHRM_8BIT_RIGHT: | ||
288 | #if GD32_DAC_DUAL_MODE | ||
289 | case DAC_DHRM_8BIT_RIGHT_DUAL: | ||
290 | #endif | ||
291 | if (channel == 0U) { | ||
292 | #if GD32_DAC_DUAL_MODE | ||
293 | dacp->params->dac->R8DH0 = (uint32_t)sample; | ||
294 | #else | ||
295 | *(&dacp->params->dac->R8DH0 + dacp->params->dataoffset) = (uint32_t)sample; | ||
296 | #endif | ||
297 | } | ||
298 | #if (GD32_HAS_DAC_CH2) | ||
299 | else { | ||
300 | dacp->params->dac->R8DH1 = (uint32_t)sample; | ||
301 | } | ||
302 | #endif | ||
303 | break; | ||
304 | default: | ||
305 | osalDbgAssert(false, "unexpected DAC mode"); | ||
306 | break; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | /** | ||
311 | * @brief Starts a DAC conversion. | ||
312 | * @details Starts an asynchronous conversion operation. | ||
313 | * @note In @p DAC_DHRM_8BIT_RIGHT mode the parameters passed to the | ||
314 | * callback are wrong because two samples are packed in a single | ||
315 | * dacsample_t element. This will not be corrected, do not rely | ||
316 | * on those parameters. | ||
317 | * @note In @p DAC_DHRM_8BIT_RIGHT_DUAL mode two samples are treated | ||
318 | * as a single 16 bits sample and packed into a single dacsample_t | ||
319 | * element. The num_channels must be set to one in the group | ||
320 | * conversion configuration structure. | ||
321 | * | ||
322 | * @param[in] dacp pointer to the @p DACDriver object | ||
323 | * | ||
324 | * @notapi | ||
325 | */ | ||
326 | void dac_lld_start_conversion(DACDriver *dacp) { | ||
327 | uint32_t n, ctl, dmamode; | ||
328 | |||
329 | /* Number of DMA operations per buffer.*/ | ||
330 | n = dacp->depth * dacp->grpp->num_channels; | ||
331 | |||
332 | /* Allocating the DMA channel.*/ | ||
333 | dacp->dma = dmaStreamAllocI(dacp->params->dmastream, | ||
334 | dacp->params->dmairqprio, | ||
335 | (gd32_dmaisr_t)dac_lld_serve_tx_interrupt, | ||
336 | (void *)dacp); | ||
337 | osalDbgAssert(dacp->dma != NULL, "unable to allocate stream"); | ||
338 | |||
339 | /* DMA settings depend on the chosen DAC mode.*/ | ||
340 | switch (dacp->config->datamode) { | ||
341 | /* Sets the DAC data register */ | ||
342 | case DAC_DHRM_12BIT_RIGHT: | ||
343 | osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); | ||
344 | |||
345 | dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->R12DH0 + | ||
346 | dacp->params->dataoffset); | ||
347 | dmamode = dacp->params->dmamode | | ||
348 | GD32_DMA_CTL_PWIDTH_HWORD | GD32_DMA_CTL_MWIDTH_HWORD; | ||
349 | break; | ||
350 | case DAC_DHRM_12BIT_LEFT: | ||
351 | osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); | ||
352 | |||
353 | dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->L12DH0 + | ||
354 | dacp->params->dataoffset); | ||
355 | dmamode = dacp->params->dmamode | | ||
356 | GD32_DMA_CTL_PWIDTH_HWORD | GD32_DMA_CTL_MWIDTH_HWORD; | ||
357 | break; | ||
358 | case DAC_DHRM_8BIT_RIGHT: | ||
359 | osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); | ||
360 | |||
361 | dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->R8DH0 + | ||
362 | dacp->params->dataoffset); | ||
363 | dmamode = dacp->params->dmamode | | ||
364 | GD32_DMA_CTL_PWIDTH_BYTE | GD32_DMA_CTL_MWIDTH_BYTE; | ||
365 | |||
366 | /* In this mode the size of the buffer is halved because two samples | ||
367 | packed in a single dacsample_t element.*/ | ||
368 | n = (n + 1) / 2; | ||
369 | break; | ||
370 | #if GD32_DAC_DUAL_MODE == TRUE | ||
371 | case DAC_DHRM_12BIT_RIGHT_DUAL: | ||
372 | osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels"); | ||
373 | |||
374 | dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->R12DH); | ||
375 | dmamode = dacp->params->dmamode | | ||
376 | GD32_DMA_CTL_PWIDTH_WORD | GD32_DMA_CTL_MWIDTH_WORD; | ||
377 | n /= 2; | ||
378 | break; | ||
379 | case DAC_DHRM_12BIT_LEFT_DUAL: | ||
380 | osalDbgAssert(dacp->grpp->num_channels == 2, "invalid number of channels"); | ||
381 | |||
382 | dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->L12DH); | ||
383 | dmamode = dacp->params->dmamode | | ||
384 | GD32_DMA_CTL_PWIDTH_WORD | GD32_DMA_CTL_MWIDTH_WORD; | ||
385 | n /= 2; | ||
386 | break; | ||
387 | case DAC_DHRM_8BIT_RIGHT_DUAL: | ||
388 | osalDbgAssert(dacp->grpp->num_channels == 1, "invalid number of channels"); | ||
389 | |||
390 | dmaStreamSetPeripheral(dacp->dma, &dacp->params->dac->R8DH); | ||
391 | dmamode = dacp->params->dmamode | | ||
392 | GD32_DMA_CTL_PWIDTH_HWORD | GD32_DMA_CTL_MWIDTH_HWORD; | ||
393 | n /= 2; | ||
394 | break; | ||
395 | #endif | ||
396 | default: | ||
397 | osalDbgAssert(false, "unexpected DAC mode"); | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | dmaStreamSetMemory0(dacp->dma, dacp->samples); | ||
402 | dmaStreamSetTransactionSize(dacp->dma, n); | ||
403 | dmaStreamSetMode(dacp->dma, dmamode | | ||
404 | GD32_DMA_CTL_ERRIE | | ||
405 | GD32_DMA_CTL_HTFIE | GD32_DMA_CTL_FTFIE); | ||
406 | dmaStreamEnable(dacp->dma); | ||
407 | |||
408 | /* DAC configuration.*/ | ||
409 | ctl = dacp->params->dac->CTL; | ||
410 | |||
411 | #if GD32_DAC_DUAL_MODE == FALSE | ||
412 | ctl &= dacp->params->regmask; | ||
413 | ctl |= (DAC_CTL_DDMAEN0 | (dacp->grpp->trigger << DAC_CTL_DTSEL0_Pos) | DAC_CTL_DTEN0 | DAC_CTL_DEN0 | dacp->config->ctl) << dacp->params->regshift; | ||
414 | #else | ||
415 | ctl = DAC_CTL_DDMAEN0 | (dacp->grpp->trigger << DAC_CTL_DTSEL0_Pos) | DAC_CTL_DTEN0 | DAC_CTL_DEN0 | dacp->config->ctl | ||
416 | | (dacp->grpp->trigger << DAC_CTL_DTSEL1_Pos) | DAC_CTL_DTEN1 | DAC_CTL_DEN1 | (dacp->config->ctl << 16); | ||
417 | #endif | ||
418 | |||
419 | dacp->params->dac->CTL = ctl; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * @brief Stops an ongoing conversion. | ||
424 | * @details This function stops the currently ongoing conversion and returns | ||
425 | * the driver in the @p DAC_READY state. If there was no conversion | ||
426 | * being processed then the function does nothing. | ||
427 | * | ||
428 | * @param[in] dacp pointer to the @p DACDriver object | ||
429 | * | ||
430 | * @iclass | ||
431 | */ | ||
432 | void dac_lld_stop_conversion(DACDriver *dacp) { | ||
433 | uint32_t ctl; | ||
434 | |||
435 | /* DMA channel disabled and released.*/ | ||
436 | dmaStreamDisable(dacp->dma); | ||
437 | dmaStreamFreeI(dacp->dma); | ||
438 | dacp->dma = NULL; | ||
439 | |||
440 | ctl = dacp->params->dac->CTL; | ||
441 | |||
442 | #if GD32_DAC_DUAL_MODE == FALSE | ||
443 | ctl &= dacp->params->regmask; | ||
444 | ctl |= (DAC_CTL_DEN0 | dacp->config->ctl) << dacp->params->regshift; | ||
445 | #else | ||
446 | if ((dacp->config->datamode == DAC_DHRM_12BIT_RIGHT_DUAL) || | ||
447 | (dacp->config->datamode == DAC_DHRM_12BIT_LEFT_DUAL) || | ||
448 | (dacp->config->datamode == DAC_DHRM_8BIT_RIGHT_DUAL)) { | ||
449 | ctl = DAC_CTL_DEN1 | (dacp->config->ctl << 16) | | ||
450 | DAC_CTL_DEN0 | dacp->config->ctl; | ||
451 | } | ||
452 | else { | ||
453 | ctl = DAC_CTL_DEN0 | dacp->config->ctl; | ||
454 | } | ||
455 | #endif | ||
456 | |||
457 | dacp->params->dac->CTL = ctl; | ||
458 | } | ||
459 | |||
460 | #endif /* HAL_USE_DAC */ | ||
461 | |||
462 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.h b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.h new file mode 100644 index 000000000..27fe38acb --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DAC/hal_dac_lld.h | |||
@@ -0,0 +1,304 @@ | |||
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 DAC/hal_dac_lld.h | ||
20 | * @brief GD32 DAC subsystem low level driver header. | ||
21 | * | ||
22 | * @addtogroup DAC | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #ifndef HAL_DAC_LLD_H | ||
27 | #define HAL_DAC_LLD_H | ||
28 | |||
29 | #if HAL_USE_DAC || defined(__DOXYGEN__) | ||
30 | |||
31 | /*===========================================================================*/ | ||
32 | /* Driver constants. */ | ||
33 | /*===========================================================================*/ | ||
34 | |||
35 | /** | ||
36 | * @name DAC trigger modes | ||
37 | * @{ | ||
38 | */ | ||
39 | #define DAC_TRG_MASK 7U | ||
40 | #define DAC_TRG(n) (n) | ||
41 | /** @} */ | ||
42 | |||
43 | /*===========================================================================*/ | ||
44 | /* Driver pre-compile time settings. */ | ||
45 | /*===========================================================================*/ | ||
46 | |||
47 | /** | ||
48 | * @name Configuration options | ||
49 | * @{ | ||
50 | */ | ||
51 | /** | ||
52 | * @brief Enables the DAC dual mode. | ||
53 | * @note In dual mode DAC second channels cannot be accessed individually. | ||
54 | */ | ||
55 | #if !defined(GD32_DAC_DUAL_MODE) || defined(__DOXYGEN__) | ||
56 | #define GD32_DAC_DUAL_MODE FALSE | ||
57 | #endif | ||
58 | |||
59 | /** | ||
60 | * @brief DAC CH1 driver enable switch. | ||
61 | * @details If set to @p TRUE the support for DAC channel 1 is included. | ||
62 | * @note The default is @p FALSE. | ||
63 | */ | ||
64 | #if !defined(GD32_DAC_USE_DAC_CH1) || defined(__DOXYGEN__) | ||
65 | #define GD32_DAC_USE_DAC_CH1 FALSE | ||
66 | #endif | ||
67 | |||
68 | /** | ||
69 | * @brief DAC CH2 driver enable switch. | ||
70 | * @details If set to @p TRUE the support for DAC channel 2 is included. | ||
71 | * @note The default is @p FALSE. | ||
72 | */ | ||
73 | #if !defined(GD32_DAC_USE_DAC_CH2) || defined(__DOXYGEN__) | ||
74 | #define GD32_DAC_USE_DAC_CH2 FALSE | ||
75 | #endif | ||
76 | |||
77 | /** | ||
78 | * @brief DAC CH1 interrupt priority level setting. | ||
79 | */ | ||
80 | #if !defined(GD32_DAC_CH1_IRQ_PRIORITY) || defined(__DOXYGEN__) | ||
81 | #define GD32_DAC_CH1_IRQ_PRIORITY 10 | ||
82 | #endif | ||
83 | |||
84 | /** | ||
85 | * @brief DAC CH2 interrupt priority level setting. | ||
86 | */ | ||
87 | #if !defined(GD32_DAC_CH2_IRQ_PRIORITY) || defined(__DOXYGEN__) | ||
88 | #define GD32_DAC_CH2_IRQ_PRIORITY 10 | ||
89 | #endif | ||
90 | |||
91 | /** | ||
92 | * @brief DAC CH1 DMA priority (0..3|lowest..highest). | ||
93 | */ | ||
94 | #if !defined(GD32_DAC_CH1_DMA_PRIORITY) || defined(__DOXYGEN__) | ||
95 | #define GD32_DAC_CH1_DMA_PRIORITY 2 | ||
96 | #endif | ||
97 | |||
98 | /** | ||
99 | * @brief DAC CH2 DMA priority (0..3|lowest..highest). | ||
100 | */ | ||
101 | #if !defined(GD32_DAC_CH2_DMA_PRIORITY) || defined(__DOXYGEN__) | ||
102 | #define GD32_DAC_CH2_DMA_PRIORITY 2 | ||
103 | #endif | ||
104 | /** @} */ | ||
105 | |||
106 | /*===========================================================================*/ | ||
107 | /* Derived constants and error checks. */ | ||
108 | /*===========================================================================*/ | ||
109 | |||
110 | /* Handling missing registry keys.*/ | ||
111 | #if !defined(GD32_HAS_DAC_CH1) | ||
112 | #define GD32_HAS_DAC_CH1 FALSE | ||
113 | #endif | ||
114 | #if !defined(GD32_HAS_DAC_CH2) | ||
115 | #define GD32_HAS_DAC_CH2 FALSE | ||
116 | #endif | ||
117 | |||
118 | #if GD32_DAC_USE_DAC_CH1 && !GD32_HAS_DAC_CH1 | ||
119 | #error "DAC CH1 not present in the selected device" | ||
120 | #endif | ||
121 | |||
122 | #if GD32_DAC_USE_DAC_CH2 && !GD32_HAS_DAC_CH2 | ||
123 | #error "DAC CH2 not present in the selected device" | ||
124 | #endif | ||
125 | |||
126 | #if GD32_DAC_USE_DAC_CH2 && GD32_DAC_DUAL_MODE | ||
127 | #error "DACx CH2 cannot be used independently in dual mode" | ||
128 | #endif | ||
129 | |||
130 | #if !GD32_DAC_USE_DAC_CH1 && !GD32_DAC_USE_DAC_CH2 | ||
131 | #error "DAC driver activated but no DAC peripheral assigned" | ||
132 | #endif | ||
133 | |||
134 | #if GD32_DAC_USE_DAC_CH1 && \ | ||
135 | !OSAL_IRQ_IS_VALID_PRIORITY(GD32_DAC_CH1_IRQ_PRIORITY) | ||
136 | #error "Invalid IRQ priority assigned to DAC CH1" | ||
137 | #endif | ||
138 | |||
139 | #if GD32_DAC_USE_DAC_CH2 && \ | ||
140 | !OSAL_IRQ_IS_VALID_PRIORITY(GD32_DAC_CH2_IRQ_PRIORITY) | ||
141 | #error "Invalid IRQ priority assigned to DAC CH2" | ||
142 | #endif | ||
143 | |||
144 | |||
145 | #if GD32_DAC_USE_DAC_CH1 && \ | ||
146 | !GD32_DMA_IS_VALID_PRIORITY(GD32_DAC_CH1_DMA_PRIORITY) | ||
147 | #error "Invalid DMA priority assigned to DAC CH1" | ||
148 | #endif | ||
149 | |||
150 | #if GD32_DAC_USE_DAC_CH2 && \ | ||
151 | !GD32_DMA_IS_VALID_PRIORITY(GD32_DAC_CH2_DMA_PRIORITY) | ||
152 | #error "Invalid DMA priority assigned to DAC CH2" | ||
153 | #endif | ||
154 | |||
155 | #if !defined(GD32_DMA_REQUIRED) | ||
156 | #define GD32_DMA_REQUIRED | ||
157 | #endif | ||
158 | |||
159 | /** | ||
160 | * @brief Max DAC channels. | ||
161 | */ | ||
162 | #if GD32_DAC_DUAL_MODE == FALSE | ||
163 | #define DAC_MAX_CHANNELS 2 | ||
164 | #else | ||
165 | #define DAC_MAX_CHANNELS 1 | ||
166 | #endif | ||
167 | |||
168 | /*===========================================================================*/ | ||
169 | /* Driver data structures and types. */ | ||
170 | /*===========================================================================*/ | ||
171 | |||
172 | /** | ||
173 | * @brief Type of a DAC channel index. | ||
174 | */ | ||
175 | typedef uint32_t dacchannel_t; | ||
176 | |||
177 | /** | ||
178 | * @brief Type representing a DAC sample. | ||
179 | */ | ||
180 | typedef uint16_t dacsample_t; | ||
181 | |||
182 | /** | ||
183 | * @brief DAC channel parameters type. | ||
184 | */ | ||
185 | typedef struct { | ||
186 | /** | ||
187 | * @brief Pointer to the DAC registers block. | ||
188 | */ | ||
189 | DAC_TypeDef *dac; | ||
190 | /** | ||
191 | * @brief DAC data registers offset. | ||
192 | */ | ||
193 | uint32_t dataoffset; | ||
194 | /** | ||
195 | * @brief DAC CR register bit offset. | ||
196 | */ | ||
197 | uint32_t regshift; | ||
198 | /** | ||
199 | * @brief DAC CR register mask. | ||
200 | */ | ||
201 | uint32_t regmask; | ||
202 | /** | ||
203 | * @brief Associated DMA stream. | ||
204 | */ | ||
205 | uint32_t dmastream; | ||
206 | /** | ||
207 | * @brief Mode bits for the DMA. | ||
208 | */ | ||
209 | uint32_t dmamode; | ||
210 | /** | ||
211 | * @brief DMA channel IRQ priority. | ||
212 | */ | ||
213 | uint32_t dmairqprio; | ||
214 | } dacparams_t; | ||
215 | |||
216 | /** | ||
217 | * @brief Possible DAC failure causes. | ||
218 | * @note Error codes are architecture dependent and should not relied | ||
219 | * upon. | ||
220 | */ | ||
221 | typedef enum { | ||
222 | DAC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */ | ||
223 | DAC_ERR_UNDERFLOW = 1 /**< DAC overflow condition. */ | ||
224 | } dacerror_t; | ||
225 | |||
226 | /** | ||
227 | * @brief Samples alignment and size mode. | ||
228 | */ | ||
229 | typedef enum { | ||
230 | DAC_DHRM_12BIT_RIGHT = 0, | ||
231 | DAC_DHRM_12BIT_LEFT = 1, | ||
232 | DAC_DHRM_8BIT_RIGHT = 2, | ||
233 | #if GD32_DAC_DUAL_MODE && !defined(__DOXYGEN__) | ||
234 | DAC_DHRM_12BIT_RIGHT_DUAL = 3, | ||
235 | DAC_DHRM_12BIT_LEFT_DUAL = 4, | ||
236 | DAC_DHRM_8BIT_RIGHT_DUAL = 5 | ||
237 | #endif | ||
238 | } dacdhrmode_t; | ||
239 | |||
240 | /*===========================================================================*/ | ||
241 | /* Driver macros. */ | ||
242 | /*===========================================================================*/ | ||
243 | |||
244 | /** | ||
245 | * @brief Low level fields of the DAC driver structure. | ||
246 | */ | ||
247 | #define dac_lld_driver_fields \ | ||
248 | /* DAC channel parameters.*/ \ | ||
249 | const dacparams_t *params; \ | ||
250 | /* Associated DMA.*/ \ | ||
251 | const gd32_dma_stream_t *dma | ||
252 | |||
253 | /** | ||
254 | * @brief Low level fields of the DAC configuration structure. | ||
255 | */ | ||
256 | #define dac_lld_config_fields \ | ||
257 | /* Initial output on DAC channels.*/ \ | ||
258 | dacsample_t init; \ | ||
259 | /* DAC data holding register mode.*/ \ | ||
260 | dacdhrmode_t datamode; \ | ||
261 | /* DAC control register lower 16 bits.*/ \ | ||
262 | uint32_t ctl | ||
263 | |||
264 | /** | ||
265 | * @brief Low level fields of the DAC group configuration structure. | ||
266 | */ | ||
267 | #define dac_lld_conversion_group_fields \ | ||
268 | /* DAC initialization data. This field contains the (not shifted) value \ | ||
269 | to be put into the TSEL field of the DAC CR register during \ | ||
270 | initialization. All other fields are handled internally.*/ \ | ||
271 | uint32_t trigger | ||
272 | |||
273 | /*===========================================================================*/ | ||
274 | /* External declarations. */ | ||
275 | /*===========================================================================*/ | ||
276 | |||
277 | #if GD32_DAC_USE_DAC_CH1 && !defined(__DOXYGEN__) | ||
278 | extern DACDriver DACD1; | ||
279 | #endif | ||
280 | |||
281 | #if GD32_DAC_USE_DAC_CH2 && !GD32_DAC_DUAL_MODE && !defined(__DOXYGEN__) | ||
282 | extern DACDriver DACD2; | ||
283 | #endif | ||
284 | |||
285 | #ifdef __cplusplus | ||
286 | extern "C" { | ||
287 | #endif | ||
288 | void dac_lld_init(void); | ||
289 | void dac_lld_start(DACDriver *dacp); | ||
290 | void dac_lld_stop(DACDriver *dacp); | ||
291 | void dac_lld_put_channel(DACDriver *dacp, | ||
292 | dacchannel_t channel, | ||
293 | dacsample_t sample); | ||
294 | void dac_lld_start_conversion(DACDriver *dacp); | ||
295 | void dac_lld_stop_conversion(DACDriver *dacp); | ||
296 | #ifdef __cplusplus | ||
297 | } | ||
298 | #endif | ||
299 | |||
300 | #endif /* HAL_USE_DAC */ | ||
301 | |||
302 | #endif /* HAL_DAC_LLD_H */ | ||
303 | |||
304 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/driver.mk b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/driver.mk new file mode 100644 index 000000000..bf1fdf5ed --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/driver.mk | |||
@@ -0,0 +1,2 @@ | |||
1 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.c | ||
2 | PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/DMA | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.c b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.c new file mode 100644 index 000000000..542842711 --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.c | |||
@@ -0,0 +1,590 @@ | |||
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 DMA/gd32_dma.c | ||
20 | * @brief DMA helper driver code. | ||
21 | * | ||
22 | * @addtogroup GD32_DMA | ||
23 | * @details DMA sharing helper driver. In the GD32 the DMA streams are a | ||
24 | * shared resource, this driver allows to allocate and free DMA | ||
25 | * streams at runtime in order to allow all the other device | ||
26 | * drivers to coordinate the access to the resource. | ||
27 | * @note The DMA ISR handlers are all declared into this module because | ||
28 | * sharing, the various device drivers can associate a callback to | ||
29 | * ISRs when allocating streams. | ||
30 | * @{ | ||
31 | */ | ||
32 | |||
33 | #include "hal.h" | ||
34 | |||
35 | /* The following macro is only defined if some driver requiring DMA services | ||
36 | has been enabled.*/ | ||
37 | #if defined(GD32_DMA_REQUIRED) || defined(__DOXYGEN__) | ||
38 | |||
39 | /*===========================================================================*/ | ||
40 | /* Driver local definitions. */ | ||
41 | /*===========================================================================*/ | ||
42 | |||
43 | /** | ||
44 | * @brief Mask of the DMA0 streams in @p dma_streams_mask. | ||
45 | */ | ||
46 | #define GD32_DMA0_STREAMS_MASK ((1U << GD32_DMA0_NUM_CHANNELS) - 1U) | ||
47 | |||
48 | /** | ||
49 | * @brief Mask of the DMA1 streams in @p dma_streams_mask. | ||
50 | */ | ||
51 | #define GD32_DMA1_STREAMS_MASK (((1U << GD32_DMA1_NUM_CHANNELS) - \ | ||
52 | 1U) << GD32_DMA0_NUM_CHANNELS) | ||
53 | |||
54 | #define DMA0_CH0_VARIANT 0 | ||
55 | #define DMA0_CH1_VARIANT 0 | ||
56 | #define DMA0_CH2_VARIANT 0 | ||
57 | #define DMA0_CH3_VARIANT 0 | ||
58 | #define DMA0_CH4_VARIANT 0 | ||
59 | #define DMA0_CH5_VARIANT 0 | ||
60 | #define DMA0_CH6_VARIANT 0 | ||
61 | #define DMA1_CH0_VARIANT 0 | ||
62 | #define DMA1_CH1_VARIANT 0 | ||
63 | #define DMA1_CH2_VARIANT 0 | ||
64 | #define DMA1_CH3_VARIANT 0 | ||
65 | #define DMA1_CH4_VARIANT 0 | ||
66 | |||
67 | /* | ||
68 | * Default ISR collision masks. | ||
69 | */ | ||
70 | #if !defined(GD32_DMA0_CH0_CMASK) | ||
71 | #define GD32_DMA0_CH0_CMASK (1U << 0U) | ||
72 | #endif | ||
73 | |||
74 | #if !defined(GD32_DMA0_CH1_CMASK) | ||
75 | #define GD32_DMA0_CH1_CMASK (1U << 1U) | ||
76 | #endif | ||
77 | |||
78 | #if !defined(GD32_DMA0_CH2_CMASK) | ||
79 | #define GD32_DMA0_CH2_CMASK (1U << 2U) | ||
80 | #endif | ||
81 | |||
82 | #if !defined(GD32_DMA0_CH3_CMASK) | ||
83 | #define GD32_DMA0_CH3_CMASK (1U << 3U) | ||
84 | #endif | ||
85 | |||
86 | #if !defined(GD32_DMA0_CH4_CMASK) | ||
87 | #define GD32_DMA0_CH4_CMASK (1U << 4U) | ||
88 | #endif | ||
89 | |||
90 | #if !defined(GD32_DMA0_CH5_CMASK) | ||
91 | #define GD32_DMA0_CH5_CMASK (1U << 5U) | ||
92 | #endif | ||
93 | |||
94 | #if !defined(GD32_DMA0_CH6_CMASK) | ||
95 | #define GD32_DMA0_CH6_CMASK (1U << 6U) | ||
96 | #endif | ||
97 | |||
98 | #if !defined(GD32_DMA1_CH0_CMASK) | ||
99 | #define GD32_DMA1_CH0_CMASK (1U << (GD32_DMA0_NUM_CHANNELS + 0U)) | ||
100 | #endif | ||
101 | |||
102 | #if !defined(GD32_DMA1_CH1_CMASK) | ||
103 | #define GD32_DMA1_CH1_CMASK (1U << (GD32_DMA0_NUM_CHANNELS + 1U)) | ||
104 | #endif | ||
105 | |||
106 | #if !defined(GD32_DMA1_CH2_CMASK) | ||
107 | #define GD32_DMA1_CH2_CMASK (1U << (GD32_DMA0_NUM_CHANNELS + 2U)) | ||
108 | #endif | ||
109 | |||
110 | #if !defined(GD32_DMA1_CH3_CMASK) | ||
111 | #define GD32_DMA1_CH3_CMASK (1U << (GD32_DMA0_NUM_CHANNELS + 3U)) | ||
112 | #endif | ||
113 | |||
114 | #if !defined(GD32_DMA1_CH4_CMASK) | ||
115 | #define GD32_DMA1_CH4_CMASK (1U << (GD32_DMA0_NUM_CHANNELS + 4U)) | ||
116 | #endif | ||
117 | |||
118 | /*===========================================================================*/ | ||
119 | /* Driver exported variables. */ | ||
120 | /*===========================================================================*/ | ||
121 | |||
122 | /** | ||
123 | * @brief DMA streams descriptors. | ||
124 | * @details This table keeps the association between an unique stream | ||
125 | * identifier and the involved physical registers. | ||
126 | * @note Don't use this array directly, use the appropriate wrapper macros | ||
127 | * instead: @p GD32_DMA0_STREAM0, @p GD32_DMA0_STREAM1 etc. | ||
128 | */ | ||
129 | const gd32_dma_stream_t _gd32_dma_streams[GD32_DMA_STREAMS] = { | ||
130 | {DMA0, DMA0_Channel0, GD32_DMA0_CH0_CMASK, DMA0_CH0_VARIANT, 0, 0, GD32_DMA0_CH0_NUMBER}, | ||
131 | {DMA0, DMA0_Channel1, GD32_DMA0_CH1_CMASK, DMA0_CH1_VARIANT, 4, 1, GD32_DMA0_CH1_NUMBER}, | ||
132 | {DMA0, DMA0_Channel2, GD32_DMA0_CH2_CMASK, DMA0_CH2_VARIANT, 8, 2, GD32_DMA0_CH2_NUMBER}, | ||
133 | {DMA0, DMA0_Channel3, GD32_DMA0_CH3_CMASK, DMA0_CH3_VARIANT, 12, 3, GD32_DMA0_CH3_NUMBER}, | ||
134 | {DMA0, DMA0_Channel4, GD32_DMA0_CH4_CMASK, DMA0_CH4_VARIANT, 16, 4, GD32_DMA0_CH4_NUMBER}, | ||
135 | {DMA0, DMA0_Channel5, GD32_DMA0_CH5_CMASK, DMA0_CH5_VARIANT, 20, 5, GD32_DMA0_CH5_NUMBER}, | ||
136 | {DMA0, DMA0_Channel6, GD32_DMA0_CH6_CMASK, DMA0_CH6_VARIANT, 24, 6, GD32_DMA0_CH6_NUMBER}, | ||
137 | {DMA1, DMA1_Channel0, GD32_DMA1_CH0_CMASK, DMA1_CH0_VARIANT, 0, 0 + GD32_DMA0_NUM_CHANNELS, GD32_DMA1_CH0_NUMBER}, | ||
138 | {DMA1, DMA1_Channel1, GD32_DMA1_CH1_CMASK, DMA1_CH1_VARIANT, 4, 1 + GD32_DMA0_NUM_CHANNELS, GD32_DMA1_CH1_NUMBER}, | ||
139 | {DMA1, DMA1_Channel2, GD32_DMA1_CH2_CMASK, DMA1_CH2_VARIANT, 8, 2 + GD32_DMA0_NUM_CHANNELS, GD32_DMA1_CH2_NUMBER}, | ||
140 | {DMA1, DMA1_Channel3, GD32_DMA1_CH3_CMASK, DMA1_CH3_VARIANT, 12, 3 + GD32_DMA0_NUM_CHANNELS, GD32_DMA1_CH3_NUMBER}, | ||
141 | {DMA1, DMA1_Channel4, GD32_DMA1_CH4_CMASK, DMA1_CH4_VARIANT, 16, 4 + GD32_DMA0_NUM_CHANNELS, GD32_DMA1_CH4_NUMBER}, | ||
142 | }; | ||
143 | |||
144 | /*===========================================================================*/ | ||
145 | /* Driver local variables and types. */ | ||
146 | /*===========================================================================*/ | ||
147 | |||
148 | /** | ||
149 | * @brief Global DMA-related data structures. | ||
150 | */ | ||
151 | static struct { | ||
152 | /** | ||
153 | * @brief Mask of the allocated streams. | ||
154 | */ | ||
155 | uint32_t allocated_mask; | ||
156 | /** | ||
157 | * @brief Mask of the enabled streams ISRs. | ||
158 | */ | ||
159 | uint32_t isr_mask; | ||
160 | /** | ||
161 | * @brief DMA IRQ redirectors. | ||
162 | */ | ||
163 | struct { | ||
164 | /** | ||
165 | * @brief DMA callback function. | ||
166 | */ | ||
167 | gd32_dmaisr_t func; | ||
168 | /** | ||
169 | * @brief DMA callback parameter. | ||
170 | */ | ||
171 | void *param; | ||
172 | } streams[GD32_DMA_STREAMS]; | ||
173 | } dma; | ||
174 | |||
175 | /*===========================================================================*/ | ||
176 | /* Driver local functions. */ | ||
177 | /*===========================================================================*/ | ||
178 | |||
179 | /*===========================================================================*/ | ||
180 | /* Driver interrupt handlers. */ | ||
181 | /*===========================================================================*/ | ||
182 | |||
183 | #if defined(GD32_DMA0_CH0_HANDLER) || defined(__DOXYGEN__) | ||
184 | /** | ||
185 | * @brief DMA0 stream 0 shared ISR. | ||
186 | * | ||
187 | * @isr | ||
188 | */ | ||
189 | OSAL_IRQ_HANDLER(GD32_DMA0_CH0_HANDLER) { | ||
190 | |||
191 | OSAL_IRQ_PROLOGUE(); | ||
192 | |||
193 | dmaServeInterrupt(GD32_DMA0_STREAM0); | ||
194 | |||
195 | OSAL_IRQ_EPILOGUE(); | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | #if defined(GD32_DMA0_CH1_HANDLER) || defined(__DOXYGEN__) | ||
200 | /** | ||
201 | * @brief DMA0 stream 1 shared ISR. | ||
202 | * | ||
203 | * @isr | ||
204 | */ | ||
205 | OSAL_IRQ_HANDLER(GD32_DMA0_CH1_HANDLER) { | ||
206 | |||
207 | OSAL_IRQ_PROLOGUE(); | ||
208 | |||
209 | dmaServeInterrupt(GD32_DMA0_STREAM1); | ||
210 | |||
211 | OSAL_IRQ_EPILOGUE(); | ||
212 | } | ||
213 | #endif | ||
214 | |||
215 | #if defined(GD32_DMA0_CH2_HANDLER) || defined(__DOXYGEN__) | ||
216 | /** | ||
217 | * @brief DMA0 stream 2 shared ISR. | ||
218 | * | ||
219 | * @isr | ||
220 | */ | ||
221 | OSAL_IRQ_HANDLER(GD32_DMA0_CH2_HANDLER) { | ||
222 | |||
223 | OSAL_IRQ_PROLOGUE(); | ||
224 | |||
225 | dmaServeInterrupt(GD32_DMA0_STREAM2); | ||
226 | |||
227 | OSAL_IRQ_EPILOGUE(); | ||
228 | } | ||
229 | #endif | ||
230 | |||
231 | #if defined(GD32_DMA0_CH3_HANDLER) || defined(__DOXYGEN__) | ||
232 | /** | ||
233 | * @brief DMA0 stream 3 shared ISR. | ||
234 | * | ||
235 | * @isr | ||
236 | */ | ||
237 | OSAL_IRQ_HANDLER(GD32_DMA0_CH3_HANDLER) { | ||
238 | |||
239 | OSAL_IRQ_PROLOGUE(); | ||
240 | |||
241 | dmaServeInterrupt(GD32_DMA0_STREAM3); | ||
242 | |||
243 | OSAL_IRQ_EPILOGUE(); | ||
244 | } | ||
245 | #endif | ||
246 | |||
247 | #if defined(GD32_DMA0_CH4_HANDLER) || defined(__DOXYGEN__) | ||
248 | /** | ||
249 | * @brief DMA0 stream 4 shared ISR. | ||
250 | * | ||
251 | * @isr | ||
252 | */ | ||
253 | OSAL_IRQ_HANDLER(GD32_DMA0_CH4_HANDLER) { | ||
254 | |||
255 | OSAL_IRQ_PROLOGUE(); | ||
256 | |||
257 | dmaServeInterrupt(GD32_DMA0_STREAM4); | ||
258 | |||
259 | OSAL_IRQ_EPILOGUE(); | ||
260 | } | ||
261 | #endif | ||
262 | |||
263 | #if defined(GD32_DMA0_CH5_HANDLER) || defined(__DOXYGEN__) | ||
264 | /** | ||
265 | * @brief DMA0 stream 5 shared ISR. | ||
266 | * | ||
267 | * @isr | ||
268 | */ | ||
269 | OSAL_IRQ_HANDLER(GD32_DMA0_CH5_HANDLER) { | ||
270 | |||
271 | OSAL_IRQ_PROLOGUE(); | ||
272 | |||
273 | dmaServeInterrupt(GD32_DMA0_STREAM5); | ||
274 | |||
275 | OSAL_IRQ_EPILOGUE(); | ||
276 | } | ||
277 | #endif | ||
278 | |||
279 | #if defined(GD32_DMA0_CH6_HANDLER) || defined(__DOXYGEN__) | ||
280 | /** | ||
281 | * @brief DMA0 stream 6 shared ISR. | ||
282 | * | ||
283 | * @isr | ||
284 | */ | ||
285 | OSAL_IRQ_HANDLER(GD32_DMA0_CH6_HANDLER) { | ||
286 | |||
287 | OSAL_IRQ_PROLOGUE(); | ||
288 | |||
289 | dmaServeInterrupt(GD32_DMA0_STREAM6); | ||
290 | |||
291 | OSAL_IRQ_EPILOGUE(); | ||
292 | } | ||
293 | #endif | ||
294 | |||
295 | #if defined(GD32_DMA1_CH0_HANDLER) || defined(__DOXYGEN__) | ||
296 | /** | ||
297 | * @brief DMA1 stream 0 shared ISR. | ||
298 | * | ||
299 | * @isr | ||
300 | */ | ||
301 | OSAL_IRQ_HANDLER(GD32_DMA1_CH0_HANDLER) { | ||
302 | |||
303 | OSAL_IRQ_PROLOGUE(); | ||
304 | |||
305 | dmaServeInterrupt(GD32_DMA1_STREAM0); | ||
306 | |||
307 | OSAL_IRQ_EPILOGUE(); | ||
308 | } | ||
309 | #endif | ||
310 | |||
311 | #if defined(GD32_DMA1_CH1_HANDLER) || defined(__DOXYGEN__) | ||
312 | /** | ||
313 | * @brief DMA1 stream 1 shared ISR. | ||
314 | * | ||
315 | * @isr | ||
316 | */ | ||
317 | OSAL_IRQ_HANDLER(GD32_DMA1_CH1_HANDLER) { | ||
318 | |||
319 | OSAL_IRQ_PROLOGUE(); | ||
320 | |||
321 | dmaServeInterrupt(GD32_DMA1_STREAM1); | ||
322 | |||
323 | OSAL_IRQ_EPILOGUE(); | ||
324 | } | ||
325 | #endif | ||
326 | |||
327 | #if defined(GD32_DMA1_CH2_HANDLER) || defined(__DOXYGEN__) | ||
328 | /** | ||
329 | * @brief DMA1 stream 2 shared ISR. | ||
330 | * | ||
331 | * @isr | ||
332 | */ | ||
333 | OSAL_IRQ_HANDLER(GD32_DMA1_CH2_HANDLER) { | ||
334 | |||
335 | OSAL_IRQ_PROLOGUE(); | ||
336 | |||
337 | dmaServeInterrupt(GD32_DMA1_STREAM2); | ||
338 | |||
339 | OSAL_IRQ_EPILOGUE(); | ||
340 | } | ||
341 | #endif | ||
342 | |||
343 | #if defined(GD32_DMA1_CH3_HANDLER) || defined(__DOXYGEN__) | ||
344 | /** | ||
345 | * @brief DMA1 stream 3 shared ISR. | ||
346 | * | ||
347 | * @isr | ||
348 | */ | ||
349 | OSAL_IRQ_HANDLER(GD32_DMA1_CH3_HANDLER) { | ||
350 | |||
351 | OSAL_IRQ_PROLOGUE(); | ||
352 | |||
353 | dmaServeInterrupt(GD32_DMA1_STREAM3); | ||
354 | |||
355 | OSAL_IRQ_EPILOGUE(); | ||
356 | } | ||
357 | #endif | ||
358 | |||
359 | #if defined(GD32_DMA1_CH4_HANDLER) || defined(__DOXYGEN__) | ||
360 | /** | ||
361 | * @brief DMA1 stream 4 shared ISR. | ||
362 | * | ||
363 | * @isr | ||
364 | */ | ||
365 | OSAL_IRQ_HANDLER(GD32_DMA1_CH4_HANDLER) { | ||
366 | |||
367 | OSAL_IRQ_PROLOGUE(); | ||
368 | |||
369 | dmaServeInterrupt(GD32_DMA1_STREAM4); | ||
370 | |||
371 | OSAL_IRQ_EPILOGUE(); | ||
372 | } | ||
373 | #endif | ||
374 | |||
375 | |||
376 | /*===========================================================================*/ | ||
377 | /* Driver exported functions. */ | ||
378 | /*===========================================================================*/ | ||
379 | |||
380 | /** | ||
381 | * @brief GD32 DMA helper initialization. | ||
382 | * | ||
383 | * @init | ||
384 | */ | ||
385 | void dmaInit(void) { | ||
386 | int i; | ||
387 | |||
388 | dma.allocated_mask = 0U; | ||
389 | dma.isr_mask = 0U; | ||
390 | for (i = 0; i < GD32_DMA_STREAMS; i++) { | ||
391 | _gd32_dma_streams[i].channel->CTL = GD32_DMA_CTL_RESET_VALUE; | ||
392 | dma.streams[i].func = NULL; | ||
393 | } | ||
394 | DMA0->INTC = 0xFFFFFFFFU; | ||
395 | DMA1->INTC = 0xFFFFFFFFU; | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * @brief Allocates a DMA stream. | ||
400 | * @details The stream is allocated and, if required, the DMA clock enabled. | ||
401 | * The function also enables the IRQ vector associated to the stream | ||
402 | * and initializes its priority. | ||
403 | * | ||
404 | * @param[in] id numeric identifiers of a specific stream or: | ||
405 | * - @p GD32_DMA_STREAM_ID_ANY for any stream. | ||
406 | * - @p GD32_DMA_STREAM_ID_ANY_DMA0 for any stream | ||
407 | * on DMA0. | ||
408 | * - @p GD32_DMA_STREAM_ID_ANY_DMA1 for any stream | ||
409 | * on DMA1. | ||
410 | * . | ||
411 | * @param[in] priority IRQ priority for the DMA stream | ||
412 | * @param[in] func handling function pointer, can be @p NULL | ||
413 | * @param[in] param a parameter to be passed to the handling function | ||
414 | * @return Pointer to the allocated @p gd32_dma_stream_t | ||
415 | * structure. | ||
416 | * @retval NULL if a/the stream is not available. | ||
417 | * | ||
418 | * @iclass | ||
419 | */ | ||
420 | const gd32_dma_stream_t *dmaStreamAllocI(uint32_t id, | ||
421 | uint32_t priority, | ||
422 | gd32_dmaisr_t func, | ||
423 | void *param) { | ||
424 | uint32_t i, startid, endid; | ||
425 | |||
426 | osalDbgCheckClassI(); | ||
427 | |||
428 | if (id < GD32_DMA_STREAMS) { | ||
429 | startid = id; | ||
430 | endid = id; | ||
431 | } else { | ||
432 | osalDbgCheck(false); | ||
433 | return NULL; | ||
434 | } | ||
435 | |||
436 | for (i = startid; i <= endid; i++) { | ||
437 | uint32_t mask = (1U << i); | ||
438 | if ((dma.allocated_mask & mask) == 0U) { | ||
439 | const gd32_dma_stream_t *dmastp = GD32_DMA_STREAM(i); | ||
440 | |||
441 | /* Installs the DMA handler.*/ | ||
442 | dma.streams[i].func = func; | ||
443 | dma.streams[i].param = param; | ||
444 | dma.allocated_mask |= mask; | ||
445 | |||
446 | /* Enabling DMA clocks required by the current streams set.*/ | ||
447 | if ((GD32_DMA0_STREAMS_MASK & mask) != 0U) { | ||
448 | rcuEnableDMA0(true); | ||
449 | } | ||
450 | |||
451 | if ((GD32_DMA1_STREAMS_MASK & mask) != 0U) { | ||
452 | rcuEnableDMA1(true); | ||
453 | } | ||
454 | |||
455 | /* Enables the associated IRQ vector if not already enabled and if a | ||
456 | callback is defined.*/ | ||
457 | if (func != NULL) { | ||
458 | if ((dma.isr_mask & dmastp->cmask) == 0U) { | ||
459 | eclicEnableVector(dmastp->vector, priority, ECLIC_DMA_TRIGGER); | ||
460 | } | ||
461 | dma.isr_mask |= mask; | ||
462 | } | ||
463 | |||
464 | /* Putting the stream in a known state.*/ | ||
465 | dmaStreamDisable(dmastp); | ||
466 | dmastp->channel->CTL = GD32_DMA_CTL_RESET_VALUE; | ||
467 | |||
468 | return dmastp; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return NULL; | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * @brief Allocates a DMA stream. | ||
477 | * @details The stream is allocated and, if required, the DMA clock enabled. | ||
478 | * The function also enables the IRQ vector associated to the stream | ||
479 | * and initializes its priority. | ||
480 | * | ||
481 | * @param[in] id numeric identifiers of a specific stream or: | ||
482 | * - @p GD32_DMA_STREAM_ID_ANY for any stream. | ||
483 | * - @p GD32_DMA_STREAM_ID_ANY_DMA0 for any stream | ||
484 | * on DMA0. | ||
485 | * - @p GD32_DMA_STREAM_ID_ANY_DMA1 for any stream | ||
486 | * on DMA1. | ||
487 | * . | ||
488 | * @param[in] priority IRQ priority for the DMA stream | ||
489 | * @param[in] func handling function pointer, can be @p NULL | ||
490 | * @param[in] param a parameter to be passed to the handling function | ||
491 | * @return Pointer to the allocated @p gd32_dma_stream_t | ||
492 | * structure. | ||
493 | * @retval NULL if a/the stream is not available. | ||
494 | * | ||
495 | * @api | ||
496 | */ | ||
497 | const gd32_dma_stream_t *dmaStreamAlloc(uint32_t id, | ||
498 | uint32_t priority, | ||
499 | gd32_dmaisr_t func, | ||
500 | void *param) { | ||
501 | const gd32_dma_stream_t *dmastp; | ||
502 | |||
503 | osalSysLock(); | ||
504 | dmastp = dmaStreamAllocI(id, priority, func, param); | ||
505 | osalSysUnlock(); | ||
506 | |||
507 | return dmastp; | ||
508 | } | ||
509 | |||
510 | /** | ||
511 | * @brief Releases a DMA stream. | ||
512 | * @details The stream is freed and, if required, the DMA clock disabled. | ||
513 | * Trying to release a unallocated stream is an illegal operation | ||
514 | * and is trapped if assertions are enabled. | ||
515 | * | ||
516 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
517 | * | ||
518 | * @iclass | ||
519 | */ | ||
520 | void dmaStreamFreeI(const gd32_dma_stream_t *dmastp) { | ||
521 | uint32_t selfindex = (uint32_t)dmastp->selfindex; | ||
522 | |||
523 | osalDbgCheck(dmastp != NULL); | ||
524 | |||
525 | /* Check if the streams is not taken.*/ | ||
526 | osalDbgAssert((dma.allocated_mask & (1 << selfindex)) != 0U, | ||
527 | "not allocated"); | ||
528 | |||
529 | /* Marks the stream as not allocated.*/ | ||
530 | dma.allocated_mask &= ~(1U << selfindex); | ||
531 | dma.isr_mask &= ~(1U << selfindex); | ||
532 | |||
533 | /* Disables the associated IRQ vector if it is no more in use.*/ | ||
534 | if ((dma.isr_mask & dmastp->cmask) == 0U) { | ||
535 | eclicDisableVector(dmastp->vector); | ||
536 | } | ||
537 | |||
538 | /* Removes the DMA handler.*/ | ||
539 | dma.streams[selfindex].func = NULL; | ||
540 | dma.streams[selfindex].param = NULL; | ||
541 | |||
542 | /* Shutting down clocks that are no more required, if any.*/ | ||
543 | if ((dma.allocated_mask & GD32_DMA0_STREAMS_MASK) == 0U) { | ||
544 | rcuDisableDMA0(); | ||
545 | } | ||
546 | if ((dma.allocated_mask & GD32_DMA1_STREAMS_MASK) == 0U) { | ||
547 | rcuDisableDMA1(); | ||
548 | } | ||
549 | } | ||
550 | |||
551 | /** | ||
552 | * @brief Releases a DMA stream. | ||
553 | * @details The stream is freed and, if required, the DMA clock disabled. | ||
554 | * Trying to release a unallocated stream is an illegal operation | ||
555 | * and is trapped if assertions are enabled. | ||
556 | * | ||
557 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
558 | * | ||
559 | * @api | ||
560 | */ | ||
561 | void dmaStreamFree(const gd32_dma_stream_t *dmastp) { | ||
562 | |||
563 | osalSysLock(); | ||
564 | dmaStreamFreeI(dmastp); | ||
565 | osalSysUnlock(); | ||
566 | } | ||
567 | |||
568 | /** | ||
569 | * @brief Serves a DMA IRQ. | ||
570 | * | ||
571 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
572 | * | ||
573 | * @special | ||
574 | */ | ||
575 | void dmaServeInterrupt(const gd32_dma_stream_t *dmastp) { | ||
576 | uint32_t flags; | ||
577 | uint32_t selfindex = (uint32_t)dmastp->selfindex; | ||
578 | |||
579 | flags = (dmastp->dma->INTF >> dmastp->shift) & GD32_DMA_INTF_MASK; | ||
580 | if (flags & dmastp->channel->CTL) { | ||
581 | dmastp->dma->INTC = flags << dmastp->shift; | ||
582 | if (dma.streams[selfindex].func) { | ||
583 | dma.streams[selfindex].func(dma.streams[selfindex].param, flags); | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | |||
588 | #endif /* GD32_DMA_REQUIRED */ | ||
589 | |||
590 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.h b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.h new file mode 100644 index 000000000..3af7b44ef --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/DMA/gd32_dma.h | |||
@@ -0,0 +1,439 @@ | |||
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 DMA/gd32_dma.h | ||
20 | * @brief DMA helper driver header. | ||
21 | |||
22 | * @addtogroup GD32_DMA | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #ifndef GD32_DMA_H | ||
27 | #define GD32_DMA_H | ||
28 | |||
29 | /*===========================================================================*/ | ||
30 | /* Driver constants. */ | ||
31 | /*===========================================================================*/ | ||
32 | |||
33 | /** | ||
34 | * @brief Total number of DMA streams. | ||
35 | * @details This is the total number of streams among all the DMA units. | ||
36 | */ | ||
37 | #define GD32_DMA_STREAMS (GD32_DMA0_NUM_CHANNELS + \ | ||
38 | GD32_DMA1_NUM_CHANNELS) | ||
39 | |||
40 | /** | ||
41 | * @brief Mask of the ISR bits passed to the DMA callback functions. | ||
42 | */ | ||
43 | #define GD32_DMA_INTF_MASK 0x0E | ||
44 | |||
45 | /** | ||
46 | * @brief Returns the request line associated to the specified stream. | ||
47 | * @note In some GD32 manuals the request line is named confusingly | ||
48 | * channel. | ||
49 | * | ||
50 | * @param[in] id the unique numeric stream identifier | ||
51 | * @param[in] c a stream/request association word, one request per | ||
52 | * nibble | ||
53 | * @return Returns the request associated to the stream. | ||
54 | */ | ||
55 | #define GD32_DMA_GETCHANNEL(id, c) \ | ||
56 | (((uint32_t)(c) >> (((uint32_t)(id) % (uint32_t)GD32_DMA0_NUM_CHANNELS) * 4U)) & 15U) | ||
57 | |||
58 | /** | ||
59 | * @brief Checks if a DMA priority is within the valid range. | ||
60 | * @param[in] prio DMA priority | ||
61 | * | ||
62 | * @retval The check result. | ||
63 | * @retval false invalid DMA priority. | ||
64 | * @retval true correct DMA priority. | ||
65 | */ | ||
66 | #define GD32_DMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U)) | ||
67 | |||
68 | /** | ||
69 | * @brief Checks if a DMA stream id is within the valid range. | ||
70 | * | ||
71 | * @param[in] id DMA stream id | ||
72 | * @retval The check result. | ||
73 | * @retval false invalid DMA channel. | ||
74 | * @retval true correct DMA channel. | ||
75 | */ | ||
76 | #define GD32_DMA_IS_VALID_STREAM(id) (((id) >= 0U) && \ | ||
77 | ((id) < GD32_DMA_STREAMS)) | ||
78 | |||
79 | /** | ||
80 | * @brief Returns an unique numeric identifier for a DMA stream. | ||
81 | * | ||
82 | * @param[in] dma the DMA unit number | ||
83 | * @param[in] stream the stream number | ||
84 | * @return An unique numeric stream identifier. | ||
85 | */ | ||
86 | #define GD32_DMA_STREAM_ID(dma, stream) \ | ||
87 | ((((dma)) * GD32_DMA0_NUM_CHANNELS) + ((stream))) | ||
88 | |||
89 | /** | ||
90 | * @brief Returns a DMA stream identifier mask. | ||
91 | * | ||
92 | * | ||
93 | * @param[in] dma the DMA unit number | ||
94 | * @param[in] stream the stream number | ||
95 | * @return A DMA stream identifier mask. | ||
96 | */ | ||
97 | #define GD32_DMA_STREAM_ID_MSK(dma, stream) \ | ||
98 | (1U << GD32_DMA_STREAM_ID(dma, stream)) | ||
99 | |||
100 | /** | ||
101 | * @brief Checks if a DMA stream unique identifier belongs to a mask. | ||
102 | * | ||
103 | * @param[in] id the stream numeric identifier | ||
104 | * @param[in] mask the stream numeric identifiers mask | ||
105 | * | ||
106 | * @retval The check result. | ||
107 | * @retval false id does not belong to the mask. | ||
108 | * @retval true id belongs to the mask. | ||
109 | */ | ||
110 | #define GD32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask))) | ||
111 | |||
112 | /** | ||
113 | * @name DMA streams identifiers | ||
114 | * @{ | ||
115 | */ | ||
116 | /** | ||
117 | * @brief Returns a pointer to a gd32_dma_stream_t structure. | ||
118 | * | ||
119 | * @param[in] id the stream numeric identifier | ||
120 | * @return A pointer to the gd32_dma_stream_t constant structure | ||
121 | * associated to the DMA stream. | ||
122 | */ | ||
123 | #define GD32_DMA_STREAM(id) (&_gd32_dma_streams[id]) | ||
124 | |||
125 | #define GD32_DMA0_STREAM0 GD32_DMA_STREAM(0) | ||
126 | #define GD32_DMA0_STREAM1 GD32_DMA_STREAM(1) | ||
127 | #define GD32_DMA0_STREAM2 GD32_DMA_STREAM(2) | ||
128 | #define GD32_DMA0_STREAM3 GD32_DMA_STREAM(3) | ||
129 | #define GD32_DMA0_STREAM4 GD32_DMA_STREAM(4) | ||
130 | #define GD32_DMA0_STREAM5 GD32_DMA_STREAM(5) | ||
131 | #define GD32_DMA0_STREAM6 GD32_DMA_STREAM(6) | ||
132 | #define GD32_DMA1_STREAM0 GD32_DMA_STREAM(GD32_DMA0_NUM_CHANNELS + 0) | ||
133 | #define GD32_DMA1_STREAM1 GD32_DMA_STREAM(GD32_DMA0_NUM_CHANNELS + 1) | ||
134 | #define GD32_DMA1_STREAM2 GD32_DMA_STREAM(GD32_DMA0_NUM_CHANNELS + 2) | ||
135 | #define GD32_DMA1_STREAM3 GD32_DMA_STREAM(GD32_DMA0_NUM_CHANNELS + 3) | ||
136 | #define GD32_DMA1_STREAM4 GD32_DMA_STREAM(GD32_DMA0_NUM_CHANNELS + 4) | ||
137 | /** @} */ | ||
138 | |||
139 | /** | ||
140 | * @name CR register constants common to all DMA types | ||
141 | * @{ | ||
142 | */ | ||
143 | #define GD32_DMA_CTL_RESET_VALUE 0x00000000U | ||
144 | #define GD32_DMA_CTL_EN DMA_CTL_CHEN | ||
145 | #define GD32_DMA_CTL_ERRIE DMA_CTL_ERRIE | ||
146 | #define GD32_DMA_CTL_HTFIE DMA_CTL_HTFIE | ||
147 | #define GD32_DMA_CTL_FTFIE DMA_CTL_FTFIE | ||
148 | #define GD32_DMA_CTL_DIR_MASK (DMA_CTL_DIR | DMA_CTL_M2M) | ||
149 | #define GD32_DMA_CTL_DIR_P2M 0U | ||
150 | #define GD32_DMA_CTL_DIR_M2P DMA_CTL_DIR | ||
151 | #define GD32_DMA_CTL_DIR_M2M DMA_CTL_M2M | ||
152 | #define GD32_DMA_CTL_CMEN DMA_CTL_CMEN | ||
153 | #define GD32_DMA_CTL_PNAGA DMA_CTL_PNAGA | ||
154 | #define GD32_DMA_CTL_MNAGA DMA_CTL_MNAGA | ||
155 | #define GD32_DMA_CTL_PWIDTH_MASK DMA_CTL_PWIDTH | ||
156 | #define GD32_DMA_CTL_PWIDTH_BYTE 0U | ||
157 | #define GD32_DMA_CTL_PWIDTH_HWORD DMA_CTL_PWIDTH_0 | ||
158 | #define GD32_DMA_CTL_PWIDTH_WORD DMA_CTL_PWIDTH_1 | ||
159 | #define GD32_DMA_CTL_MWIDTH_MASK DMA_CTL_MWIDTH | ||
160 | #define GD32_DMA_CTL_MWIDTH_BYTE 0U | ||
161 | #define GD32_DMA_CTL_MWIDTH_HWORD DMA_CTL_MWIDTH_0 | ||
162 | #define GD32_DMA_CTL_MWIDTH_WORD DMA_CTL_MWIDTH_1 | ||
163 | #define GD32_DMA_CTL_SIZE_MASK (GD32_DMA_CTL_PWIDTH_MASK | \ | ||
164 | GD32_DMA_CTL_MWIDTH_MASK) | ||
165 | #define GD32_DMA_CTL_PRIO_MASK DMA_CTL_PRIO | ||
166 | #define GD32_DMA_CTL_PRIO(n) ((n) << 12U) | ||
167 | /** @} */ | ||
168 | |||
169 | /** | ||
170 | * @name Request line selector macro | ||
171 | * @{ | ||
172 | */ | ||
173 | #define GD32_DMA_CTL_CHSEL_MASK 0U | ||
174 | #define GD32_DMA_CTL_CHSEL(n) 0U | ||
175 | /** @} */ | ||
176 | |||
177 | /** | ||
178 | * @name Status flags passed to the ISR callbacks | ||
179 | * @{ | ||
180 | */ | ||
181 | #define GD32_DMA_INTF_FEIF 0U | ||
182 | #define GD32_DMA_INTF_ERRIF DMA_INTF_ERRIF0 | ||
183 | #define GD32_DMA_INTF_HTFIF DMA_INTF_HTFIF0 | ||
184 | #define GD32_DMA_INTF_FTFIF DMA_INTF_FTFIF0 | ||
185 | /** @} */ | ||
186 | |||
187 | /*===========================================================================*/ | ||
188 | /* Driver pre-compile time settings. */ | ||
189 | /*===========================================================================*/ | ||
190 | |||
191 | /*===========================================================================*/ | ||
192 | /* Derived constants and error checks. */ | ||
193 | /*===========================================================================*/ | ||
194 | |||
195 | #if !defined(GD32_DMA0_NUM_CHANNELS) | ||
196 | #error "GD32_DMA0_NUM_CHANNELS not defined in registry" | ||
197 | #endif | ||
198 | |||
199 | #if !defined(GD32_DMA1_NUM_CHANNELS) | ||
200 | #error "GD32_DMA1_NUM_CHANNELS not defined in registry" | ||
201 | #endif | ||
202 | |||
203 | #if (GD32_DMA0_NUM_CHANNELS < 0) || (GD32_DMA0_NUM_CHANNELS > 7) | ||
204 | #error "unsupported channels configuration" | ||
205 | #endif | ||
206 | |||
207 | #if (GD32_DMA1_NUM_CHANNELS < 0) || (GD32_DMA1_NUM_CHANNELS > 5) | ||
208 | #error "unsupported channels configuration" | ||
209 | #endif | ||
210 | |||
211 | /*===========================================================================*/ | ||
212 | /* Driver data structures and types. */ | ||
213 | /*===========================================================================*/ | ||
214 | |||
215 | /** | ||
216 | * @brief Type of a DMA callback. | ||
217 | * | ||
218 | * @param[in] p parameter for the registered function | ||
219 | * @param[in] flags pre-shifted content of the ISR register, the bits | ||
220 | * are aligned to bit zero | ||
221 | */ | ||
222 | typedef void (*gd32_dmaisr_t)(void *p, uint32_t flags); | ||
223 | |||
224 | /** | ||
225 | * @brief GD32 DMA stream descriptor structure. | ||
226 | */ | ||
227 | typedef struct { | ||
228 | DMA_TypeDef *dma; /**< @brief Associated DMA. */ | ||
229 | DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */ | ||
230 | uint32_t cmask; /**< @brief Mask of streams sharing | ||
231 | the same ISR. */ | ||
232 | uint8_t dummy; /**< @brief Filler. */ | ||
233 | uint8_t shift; /**< @brief Bit offset in ISR, IFCR | ||
234 | and CSELR registers. */ | ||
235 | uint8_t selfindex; /**< @brief Index to self in array. */ | ||
236 | uint8_t vector; /**< @brief Associated IRQ vector. */ | ||
237 | } gd32_dma_stream_t; | ||
238 | |||
239 | /*===========================================================================*/ | ||
240 | /* Driver macros. */ | ||
241 | /*===========================================================================*/ | ||
242 | |||
243 | /** | ||
244 | * @name Macro Functions | ||
245 | * @{ | ||
246 | */ | ||
247 | /** | ||
248 | * @brief Associates a peripheral data register to a DMA stream. | ||
249 | * @note This function can be invoked in both ISR or thread context. | ||
250 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
251 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
252 | * | ||
253 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
254 | * @param[in] addr value to be written in the PADDR register | ||
255 | * | ||
256 | * @special | ||
257 | */ | ||
258 | #define dmaStreamSetPeripheral(dmastp, addr) { \ | ||
259 | (dmastp)->channel->PADDR = (uint32_t)(addr); \ | ||
260 | } | ||
261 | |||
262 | /** | ||
263 | * @brief Associates a memory destination to a DMA stream. | ||
264 | * @note This function can be invoked in both ISR or thread context. | ||
265 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
266 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
267 | * | ||
268 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
269 | * @param[in] addr value to be written in the MADDR register | ||
270 | * | ||
271 | * @special | ||
272 | */ | ||
273 | #define dmaStreamSetMemory0(dmastp, addr) { \ | ||
274 | (dmastp)->channel->MADDR = (uint32_t)(addr); \ | ||
275 | } | ||
276 | |||
277 | /** | ||
278 | * @brief Sets the number of transfers to be performed. | ||
279 | * @note This function can be invoked in both ISR or thread context. | ||
280 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
281 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
282 | * | ||
283 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
284 | * @param[in] size value to be written in the CNT register | ||
285 | * | ||
286 | * @special | ||
287 | */ | ||
288 | #define dmaStreamSetTransactionSize(dmastp, size) { \ | ||
289 | (dmastp)->channel->CNT = (uint32_t)(size); \ | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * @brief Returns the number of transfers to be performed. | ||
294 | * @note This function can be invoked in both ISR or thread context. | ||
295 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
296 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
297 | * | ||
298 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
299 | * @return The number of transfers to be performed. | ||
300 | * | ||
301 | * @special | ||
302 | */ | ||
303 | #define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->channel->CNT)) | ||
304 | |||
305 | /** | ||
306 | * @brief Programs the stream mode settings. | ||
307 | * @note This function can be invoked in both ISR or thread context. | ||
308 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
309 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
310 | * | ||
311 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
312 | * @param[in] mode value to be written in the CCR register | ||
313 | * | ||
314 | * @special | ||
315 | */ | ||
316 | #define dmaStreamSetMode(dmastp, mode) { \ | ||
317 | (dmastp)->channel->CTL = (uint32_t)(mode); \ | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * @brief DMA stream enable. | ||
322 | * @note This function can be invoked in both ISR or thread context. | ||
323 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
324 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
325 | * | ||
326 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
327 | * | ||
328 | * @special | ||
329 | */ | ||
330 | #define dmaStreamEnable(dmastp) { \ | ||
331 | (dmastp)->channel->CTL |= GD32_DMA_CTL_EN; \ | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * @brief DMA stream disable. | ||
336 | * @details The function disables the specified stream and then clears any | ||
337 | * pending interrupt. | ||
338 | * @note This function can be invoked in both ISR or thread context. | ||
339 | * @note Interrupts enabling flags are set to zero after this call, see | ||
340 | * bug 3607518. | ||
341 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
342 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
343 | * | ||
344 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
345 | * | ||
346 | * @special | ||
347 | */ | ||
348 | #define dmaStreamDisable(dmastp) { \ | ||
349 | (dmastp)->channel->CTL &= ~(GD32_DMA_CTL_FTFIE | GD32_DMA_CTL_HTFIE | \ | ||
350 | GD32_DMA_CTL_ERRIE | GD32_DMA_CTL_EN); \ | ||
351 | dmaStreamClearInterrupt(dmastp); \ | ||
352 | } | ||
353 | |||
354 | /** | ||
355 | * @brief DMA stream interrupt sources clear. | ||
356 | * @note This function can be invoked in both ISR or thread context. | ||
357 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
358 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
359 | * | ||
360 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
361 | * | ||
362 | * @special | ||
363 | */ | ||
364 | #define dmaStreamClearInterrupt(dmastp) { \ | ||
365 | (dmastp)->dma->INTC = GD32_DMA_INTF_MASK << (dmastp)->shift; \ | ||
366 | } | ||
367 | |||
368 | /** | ||
369 | * @brief Starts a memory to memory operation using the specified stream. | ||
370 | * @note The default transfer data mode is "byte to byte" but it can be | ||
371 | * changed by specifying extra options in the @p mode parameter. | ||
372 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
373 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
374 | * | ||
375 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
376 | * @param[in] mode value to be written in the CCR register, this value | ||
377 | * is implicitly ORed with: | ||
378 | * - @p GD32_DMA_CTL_MNAGA | ||
379 | * - @p GD32_DMA_CTL_PNAGA | ||
380 | * - @p GD32_DMA_CTL_DIR_M2M | ||
381 | * - @p GD32_DMA_CTL_EN | ||
382 | * . | ||
383 | * @param[in] src source address | ||
384 | * @param[in] dst destination address | ||
385 | * @param[in] n number of data units to copy | ||
386 | */ | ||
387 | #define dmaStartMemCopy(dmastp, mode, src, dst, n) { \ | ||
388 | dmaStreamSetPeripheral(dmastp, src); \ | ||
389 | dmaStreamSetMemory0(dmastp, dst); \ | ||
390 | dmaStreamSetTransactionSize(dmastp, n); \ | ||
391 | dmaStreamSetMode(dmastp, (mode) | \ | ||
392 | GD32_DMA_CTL_MNAGA | GD32_DMA_CTL_PNAGA | \ | ||
393 | GD32_DMA_CTL_DIR_M2M | GD32_DMA_CTL_EN); \ | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * @brief Polled wait for DMA transfer end. | ||
398 | * @pre The stream must have been allocated using @p dmaStreamAlloc(). | ||
399 | * @post After use the stream can be released using @p dmaStreamRelease(). | ||
400 | * | ||
401 | * @param[in] dmastp pointer to a gd32_dma_stream_t structure | ||
402 | */ | ||
403 | #define dmaWaitCompletion(dmastp) { \ | ||
404 | while ((dmastp)->channel->CNT > 0U) \ | ||
405 | ; \ | ||
406 | dmaStreamDisable(dmastp); \ | ||
407 | } | ||
408 | /** @} */ | ||
409 | |||
410 | /*===========================================================================*/ | ||
411 | /* External declarations. */ | ||
412 | /*===========================================================================*/ | ||
413 | |||
414 | #if !defined(__DOXYGEN__) | ||
415 | extern const gd32_dma_stream_t _gd32_dma_streams[GD32_DMA_STREAMS]; | ||
416 | #endif | ||
417 | |||
418 | #ifdef __cplusplus | ||
419 | extern "C" { | ||
420 | #endif | ||
421 | void dmaInit(void); | ||
422 | const gd32_dma_stream_t *dmaStreamAllocI(uint32_t id, | ||
423 | uint32_t priority, | ||
424 | gd32_dmaisr_t func, | ||
425 | void *param); | ||
426 | const gd32_dma_stream_t *dmaStreamAlloc(uint32_t id, | ||
427 | uint32_t priority, | ||
428 | gd32_dmaisr_t func, | ||
429 | void *param); | ||
430 | void dmaStreamFreeI(const gd32_dma_stream_t *dmastp); | ||
431 | void dmaStreamFree(const gd32_dma_stream_t *dmastp); | ||
432 | void dmaServeInterrupt(const gd32_dma_stream_t *dmastp); | ||
433 | #ifdef __cplusplus | ||
434 | } | ||
435 | #endif | ||
436 | |||
437 | #endif /* GD32_DMA_H */ | ||
438 | |||
439 | /** @} */ | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/GPIO/driver.mk b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/GPIO/driver.mk new file mode 100644 index 000000000..2f0fca3ff --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/GPIO/driver.mk | |||
@@ -0,0 +1,9 @@ | |||
1 | ifeq ($(USE_SMART_BUILD),yes) | ||
2 | ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),) | ||
3 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/GPIO/hal_pal_lld.c | ||
4 | endif | ||
5 | else | ||
6 | PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/GPIO/hal_pal_lld.c | ||
7 | endif | ||
8 | |||
9 | PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/GD/GD32VF103/GPIO | ||
diff --git a/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/GPIO/hal_pal_lld.c b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/GPIO/hal_pal_lld.c new file mode 100644 index 000000000..3d0768d69 --- /dev/null +++ b/lib/chibios-contrib/os/hal/ports/GD/GD32VF103/GPIO/hal_pal_lld.c | |||
@@ -0,0 +1,286 @@ | |||
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 GPIO/hal_pal_lld.c | ||
20 | * @brief GD32 PAL low level driver code. | ||
21 | * | ||
22 | * @addtogroup PAL | ||
23 | * @{ | ||
24 | */ | ||
25 | |||
26 | #include "hal.h" | ||
27 | |||
28 | #if HAL_USE_PAL || defined(__DOXYGEN__) | ||
29 | |||
30 | /*===========================================================================*/ | ||
31 | /* Driver local definitions. */ | ||
32 | /*===========================================================================*/ | ||
33 |