Paparazzi UAS  v5.15_devel-88-gb3ad7fe
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
hal_stm32_dma.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2019 Alexandre Bustico, Gautier Hattenberger
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
29 #pragma once
30 
31 #include <ch.h>
32 #include <hal.h>
33 
34 
39 #if !defined(STM32_DMA_USE_WAIT) || defined(__DOXYGEN__)
40 #define STM32_DMA_USE_WAIT TRUE
41 #endif
42 
47 #if !defined(STM32_DMA_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
48 #define STM32_DMA_USE_MUTUAL_EXCLUSION FALSE
49 #endif
50 
51 #if !defined(STM32_DMA_SUPPORTS_CSELR) || defined(__DOXYGEN__)
52 #define STM32_DMA_SUPPORTS_CSELR FALSE
53 #endif
54 
55 
59 typedef enum {
60  DMA_UNINIT = 0,
61  DMA_STOP = 1,
62  DMA_READY = 2,
63  DMA_ACTIVE = 3,
65  DMA_ERROR = 5
66 } dmastate_t;
67 
73 typedef enum {
78 
82 typedef enum {
87 
91 typedef struct DMADriver DMADriver;
92 
101 typedef void (*dmacallback_t)(DMADriver *dmap, void *buffer, const size_t n);
102 
103 
111 typedef void (*dmaerrorcallback_t)(DMADriver *dmap, dmaerrormask_t err);
112 
113 
114 
115 /*===========================================================================*/
116 /* Driver macros. */
117 /*===========================================================================*/
118 #if (STM32_DMA_USE_WAIT == TRUE) || defined(__DOXYGEN__)
119 
131 #define _dma_reset_i(dmap) \
132  osalThreadResumeI(&(dmap)->thread, MSG_RESET)
133 
141 #define _dma_reset_s(dmap) \
142  osalThreadResumeS(&(dmap)->thread, MSG_RESET)
143 
151 #define _dma_wakeup_isr(dmap) { \
152  osalSysLockFromISR(); \
153  osalThreadResumeI(&(dmap)->thread, MSG_OK); \
154  osalSysUnlockFromISR(); \
155  }
156 
164 #define _dma_timeout_isr(dmap) { \
165  osalSysLockFromISR(); \
166  osalThreadResumeI(&(dmap)->thread, MSG_TIMEOUT); \
167  osalSysUnlockFromISR(); \
168  }
169 #else /* !STM32_DMA_USE_WAIT */
170 #define _dma_reset_i(dmap)
171 #define _dma_reset_s(dmap)
172 #define _dma_wakeup_isr(dmap)
173 #define _dma_timeout_isr(dmap)
174 #endif /* !STM32_DMA_USE_WAIT */
175 
188 static inline void _dma_isr_half_code(DMADriver *dmap);
189 
190 
205 static inline void _dma_isr_full_code(DMADriver *dmap);
206 
207 
223 static inline void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err);
224 
225 
226 
227 #ifdef __cplusplus
228 extern "C" {
229 #endif
230 
239 typedef struct {
245 
246 #if STM32_DMA_SUPPORTS_CSELR
247 
251  union {
252  uint8_t request; // STM terminology for dmaV1
253  uint8_t channel; // ChibiOS terminology for both dmaV1 and dmaV2 (portability)
254  };
255 #elif STM32_DMA_ADVANCED
257 #endif
258 
263 
264 
269 
270 
274  bool circular;
275 
276 
281 
286 #if STM32_DMA_USE_ASYNC_TIMOUT
287 
291  sysinterval_t timeout;
292 #endif
293 
294 
299 
300 
305 
310 
314  uint8_t psize; // 1,2,4
315 
319  uint8_t msize; // 1,2,4
320 #if STM32_DMA_ADVANCED
321 #define STM32_DMA_FIFO_SIZE 4 // hardware specification for dma V2
322 
326  uint8_t pburst; // 0(burst disabled), 4, 8, 16
327 
331  uint8_t mburst; // 0(burst disabled), 4, 8, 16
332 
336  uint8_t fifo; // 0(fifo disabled), 1, 2, 3, 4 : 25, 50, 75, 100%
337 
341  bool periph_inc_size_4; // PINCOS bit
342 
346  bool transfert_end_ctrl_by_periph; // PFCTRL bit
347 #endif
348 } DMAConfig;
349 
350 
354 struct DMADriver {
358  const stm32_dma_stream_t *dmastream;
359 
364 
365 #if STM32_DMA_USE_WAIT || defined(__DOXYGEN__)
366 
369  thread_reference_t thread;
370 #endif
371 #if STM32_DMA_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
372 
375  mutex_t mutex;
376 #endif /* STM32_DMA_USE_MUTUAL_EXCLUSION */
377 #if STM32_DMA_USE_ASYNC_TIMOUT
378 
381  uint8_t *volatile currPtr;
382 
386  virtual_timer_t vt;
387 #endif
388 
393  void *mem0p;
394 
399 
403  size_t size;
404 
409 
410 
415 };
416 
417 
418 
419 void dmaObjectInit(DMADriver *dmap);
420 bool dmaStart(DMADriver *dmap, const DMAConfig *cfg);
421 void dmaStop(DMADriver *dmap);
422 
423 #if STM32_DMA_USE_WAIT == TRUE
424 msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size,
425  sysinterval_t timeout);
426 // helper
427 static inline msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
428 {
429  return dmaTransfertTimeout(dmap, periphp, mem0p, size, TIME_INFINITE);
430 }
431 #endif
432 #if STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE
433 void dmaAcquireBus(DMADriver *dmap);
434 void dmaReleaseBus(DMADriver *dmap);
435 #endif
436 bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
437 void dmaStopTransfert(DMADriver *dmap);
438 
439 bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
440 void dmaStopTransfertI(DMADriver *dmap);
441 
442 
443 // low level driver
444 
445 bool dma_lld_start(DMADriver *dmap);
446 void dma_lld_stop(DMADriver *dmap);
447 
448 
449 bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
450 
451 
453 
454 #if STM32_DMA_USE_ASYNC_TIMOUT
455 void dma_lld_serve_timeout_interrupt(void *arg);
456 #endif
457 
458 #if STM32_DMA_USE_ASYNC_TIMOUT
459 typedef enum {FROM_TIMOUT_CODE, FROM_HALF_CODE, FROM_FULL_CODE, FROM_NON_CIRCULAR_CODE} CbCallContext;
460 static inline void async_timout_enabled_call_end_cb(DMADriver *dmap, const CbCallContext context)
461 {
462  uint8_t *const baseAddr = dmap->currPtr;
463  const size_t fullSize = dmap->size;
464  const size_t halfSize = fullSize / 2;
465  size_t rem = 0;
466  uint8_t *const basePtr = (uint8_t *) dmap->mem0p;
467  uint8_t *const midPtr = ((uint8_t *) dmap->mem0p) + (dmap->config->msize * halfSize);
468  uint8_t *const endPtr = ((uint8_t *) dmap->mem0p) + (dmap->config->msize * fullSize);
469 
470 
471  switch (context) {
472  case (FROM_HALF_CODE) :
473  if (midPtr > baseAddr) {
474  rem = (midPtr - baseAddr) / dmap->config->msize;
475  dmap->currPtr = midPtr;
476  }
477  break;
478 
479  case (FROM_FULL_CODE) :
480  case (FROM_NON_CIRCULAR_CODE) :
481  rem = (endPtr - baseAddr) / dmap->config->msize;
482  dmap->currPtr = basePtr;
483  break;
484 
485  case (FROM_TIMOUT_CODE) : {
486  const size_t dmaCNT = dmaStreamGetTransactionSize(dmap->dmastream);
487  const size_t index = (baseAddr - basePtr) / dmap->config->msize;
488 
489  // if following test fail, it's because DMACNT has rollover during the ISR,
490  // so that we can safely ignore this TIMOUT event since a fullcode ISR will follow
491  // briefly
492  if (fullSize >= (dmaCNT + index)) {
493  rem = (fullSize - dmaCNT - index);
494  dmap->currPtr = baseAddr + (rem * dmap->config->msize);
495  }
496  }
497  break;
498  }
499 
500  if (dmap->config->end_cb != NULL && (rem > 0)) {
501  dmap->config->end_cb(dmap, baseAddr, rem);
502  }
503 }
504 #endif
505 
506 static inline void _dma_isr_half_code(DMADriver *dmap)
507 {
508 #if STM32_DMA_USE_ASYNC_TIMOUT
509  if (dmap->config->timeout != TIME_INFINITE) {
510  chSysLockFromISR();
511  chVTSetI(&dmap->vt, dmap->config->timeout,
512  &dma_lld_serve_timeout_interrupt, (void *) dmap);
513  chSysUnlockFromISR();
514  }
515  async_timout_enabled_call_end_cb(dmap, FROM_HALF_CODE);
516 #else
517  if (dmap->config->end_cb != NULL) {
518  dmap->config->end_cb(dmap, dmap->mem0p, dmap->size / 2);
519  }
520 #endif
521 }
522 
523 static inline void _dma_isr_full_code(DMADriver *dmap)
524 {
525  if (dmap->config->circular) {
526 #if STM32_DMA_USE_ASYNC_TIMOUT
527  if (dmap->config->timeout != TIME_INFINITE) {
528  chSysLockFromISR();
529  chVTSetI(&dmap->vt, dmap->config->timeout,
530  &dma_lld_serve_timeout_interrupt, (void *) dmap);
531  chSysUnlockFromISR();
532  }
533  async_timout_enabled_call_end_cb(dmap, FROM_FULL_CODE);
534 #else
535  /* Callback handling.*/
536  if (dmap->config->end_cb != NULL) {
537  if (dmap->size > 1) {
538  /* Invokes the callback passing the 2nd half of the buffer.*/
539  const size_t half_index = dmap->size / 2;
540  const uint8_t *byte_array_p = ((uint8_t *) dmap->mem0p) +
541  dmap->config->msize * half_index;
542  dmap->config->end_cb(dmap, (void *) byte_array_p, half_index);
543  } else {
544  /* Invokes the callback passing the whole buffer.*/
545  dmap->config->end_cb(dmap, dmap->mem0p, dmap->size);
546  }
547  }
548 #endif
549  } else { // not circular
550  /* End transfert.*/
551 #if STM32_DMA_USE_ASYNC_TIMOUT
552  if (dmap->config->timeout != TIME_INFINITE) {
553  chSysLockFromISR();
554  chVTResetI(&dmap->vt);
555  chSysUnlockFromISR();
556  }
557 #endif
559  if (dmap->config->end_cb != NULL) {
560  dmap->state = DMA_COMPLETE;
561  /* Invoke the callback passing the whole buffer.*/
562 #if STM32_DMA_USE_ASYNC_TIMOUT
563  async_timout_enabled_call_end_cb(dmap, FROM_NON_CIRCULAR_CODE);
564 #else
565  dmap->config->end_cb(dmap, dmap->mem0p, dmap->size);
566 #endif
567  if (dmap->state == DMA_COMPLETE) {
568  dmap->state = DMA_READY;
569  }
570  } else {
571  dmap->state = DMA_READY;
572  }
573  _dma_wakeup_isr(dmap);
574  }
575 }
576 
577 static inline void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err)
578 {
580  if (dmap->config->error_cb != NULL) {
581  dmap->state = DMA_ERROR;
582  dmap->config->error_cb(dmap, err);
583  if (dmap->state == DMA_ERROR) {
584  dmap->state = DMA_READY;
585  }
586  } else {
587  dmap->state = DMA_READY;
588  }
589  _dma_timeout_isr(dmap);
590 }
591 
592 
593 #ifdef __cplusplus
594 }
595 #endif
Ready.
Definition: hal_stm32_dma.h:62
void(* dmacallback_t)(DMADriver *dmap, void *buffer, const size_t n)
DMA notification callback type.
static float timeout
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
Definition: hal_stm32_dma.c:85
void dmaObjectInit(DMADriver *dmap)
Definition: hal_stm32_dma.c:53
void dmaStop(DMADriver *dmap)
Deactivates the DMA peripheral.
static void _dma_isr_full_code(DMADriver *dmap)
Common ISR code, full buffer event.
dmadirection_t
DMA transfert direction.
Definition: hal_stm32_dma.h:82
bool inc_peripheral_addr
Enable increment of peripheral address after each transfert.
dmaerrormask_t
Possible DMA failure causes.
Definition: hal_stm32_dma.h:73
#define _dma_timeout_isr(dmap)
Wakes up the waiting thread with a timeout message.
bool dma_lld_start(DMADriver *dmap)
Configures and activates the DMA peripheral.
Transfert error.
Definition: hal_stm32_dma.h:65
DMA FIFO overrun or underrun.
Definition: hal_stm32_dma.h:76
uint32_t dmamode
hold DMA CR register for the stream
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
void dmaAcquireBus(DMADriver *dmap)
Gains exclusive access to the DMA peripheral.
void dmaStopTransfertI(DMADriver *dmap)
Stops an ongoing transaction.
bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
void dma_lld_stop_transfert(DMADriver *dmap)
Stops an ongoing transaction.
uint32_t stream
stream associated with transaction
void dma_lld_stop(DMADriver *dmap)
Deactivates the DMA peripheral.
void dmaReleaseBus(DMADriver *dmap)
Releases exclusive access to the DMA peripheral.
#define _dma_wakeup_isr(dmap)
Wakes up the waiting thread.
bool inc_memory_addr
Enable increment of memory address after each transfert.
static pthread_mutex_t mutex
Transfert complete.
Definition: hal_stm32_dma.h:64
dmaerrorcallback_t error_cb
Error callback or NULL.
dmadirection_t direction
DMA transaction direction.
DMA transfer failure.
Definition: hal_stm32_dma.h:74
dmacallback_t end_cb
Callback function associated to the stream or NULL.
dmastate_t state
Driver state.
msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size, sysinterval_t timeout)
Performs a DMA transaction.
dmastate_t
Driver state machine possible states.
Definition: hal_stm32_dma.h:59
MEMORY to MEMORY.
Definition: hal_stm32_dma.h:85
uint8_t psize
DMA peripheral data granurality in bytes (1,2,4)
PERIPHERAL to MEMORY.
Definition: hal_stm32_dma.h:83
bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
bool circular
Enables the circular buffer mode for the stream.
DMA stream configuration structure.
static void _dma_isr_half_code(DMADriver *dmap)
Common ISR code, half buffer event.
uint8_t dma_priority
DMA priority (1 .
unsigned long uint32_t
Definition: types.h:18
DMA Direct Mode failure.
Definition: hal_stm32_dma.h:75
Stopped.
Definition: hal_stm32_dma.h:61
MEMORY to PERIPHERAL.
Definition: hal_stm32_dma.h:84
size_t size
hold size of current transaction
unsigned char uint8_t
Definition: types.h:14
const stm32_dma_stream_t * dmastream
DMA stream associated with peripheral or memory.
uint8_t irq_priority
DMA IRQ priority (2 .
void(* dmaerrorcallback_t)(DMADriver *dmap, dmaerrormask_t err)
DMA error callback type.
Transfering.
Definition: hal_stm32_dma.h:63
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
uint8_t msize
DMA memory data granurality in bytes (1,2,4)
Not initialized.
Definition: hal_stm32_dma.h:60
uint8_t controller
controller associated with stream
static uint8_t channel
Definition: ADS8344.c:80
static void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err)
Common ISR code, error event.
static msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
void * mem0p
memory address
const DMAConfig * config
Current configuration data.
Structure representing a DMA driver.