Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
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 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
42 #if !defined(STM32_DMA_USE_WAIT) || defined(__DOXYGEN__)
43 #define STM32_DMA_USE_WAIT TRUE
44 #endif
45 
50 #if !defined(STM32_DMA_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
51 #define STM32_DMA_USE_MUTUAL_EXCLUSION FALSE
52 #endif
53 
54 #if !defined(STM32_DMA_SUPPORTS_CSELR) || defined(__DOXYGEN__)
55 #define STM32_DMA_SUPPORTS_CSELR FALSE
56 #endif
57 
58 
62 typedef enum {
63  DMA_UNINIT = 0,
64  DMA_STOP = 1,
65  DMA_READY = 2,
66  DMA_ACTIVE = 3,
68  DMA_ERROR = 5
69 } dmastate_t;
70 
76 typedef enum {
79  DMA_ERR_FIFO_ERROR = 1U << 2U,
80  DMA_ERR_FIFO_FULL = 1U << 3U,
81  DMA_ERR_FIFO_EMPTY = 1U << 4U,
83 
87 typedef enum {
92 
96 typedef struct DMADriver DMADriver;
97 
106 typedef void (*dmacallback_t)(DMADriver *dmap, void *buffer, const size_t n);
107 
108 
116 typedef void (*dmaerrorcallback_t)(DMADriver *dmap, dmaerrormask_t err);
117 
118 
119 
120 /*===========================================================================*/
121 /* Driver macros. */
122 /*===========================================================================*/
123 #if (STM32_DMA_USE_WAIT == TRUE) || defined(__DOXYGEN__)
124 
136 #define _dma_reset_i(dmap) \
137  osalThreadResumeI(&(dmap)->thread, MSG_RESET)
138 
146 #define _dma_reset_s(dmap) \
147  osalThreadResumeS(&(dmap)->thread, MSG_RESET)
148 
156 #define _dma_wakeup_isr(dmap) { \
157  osalSysLockFromISR(); \
158  osalThreadResumeI(&(dmap)->thread, MSG_OK); \
159  osalSysUnlockFromISR(); \
160  }
161 
169 #define _dma_timeout_isr(dmap) { \
170  osalSysLockFromISR(); \
171  osalThreadResumeI(&(dmap)->thread, MSG_TIMEOUT); \
172  osalSysUnlockFromISR(); \
173  }
174 #else /* !STM32_DMA_USE_WAIT */
175 #define _dma_reset_i(dmap)
176 #define _dma_reset_s(dmap)
177 #define _dma_wakeup_isr(dmap)
178 #define _dma_timeout_isr(dmap)
179 #endif /* !STM32_DMA_USE_WAIT */
180 
193 static inline void _dma_isr_half_code(DMADriver *dmap);
194 
195 
210 static inline void _dma_isr_full_code(DMADriver *dmap);
211 
212 
228 static inline void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err);
229 
230 
231 
232 
241 typedef struct {
247 
248 #if STM32_DMA_SUPPORTS_CSELR
249 
253  union {
254  uint8_t request; // STM terminology for dmaV1
255  uint8_t channel; // ChibiOS terminology for both dmaV1 and dmaV2 (portability)
256  };
257 #elif STM32_DMA_ADVANCED
259 #endif
260 
265 
266 
271 
272 
276  bool circular;
277 
278 
283 
288 #if STM32_DMA_USE_ASYNC_TIMOUT
289 
293  sysinterval_t timeout;
294 #endif
295 
296 
301 
302 
307 
312 
316  uint8_t psize; // 1,2,4
317 
321  uint8_t msize; // 1,2,4
322 #if __DCACHE_PRESENT
323 
326 bool dcache_memory_in_use;
327 #endif
328 #if STM32_DMA_ADVANCED
329 #define STM32_DMA_FIFO_SIZE 16 // hardware specification for dma V2
330 
334  uint8_t pburst; // 0(burst disabled), 4, 8, 16
335 
339  uint8_t mburst; // 0(burst disabled), 4, 8, 16
340 
344  uint8_t fifo; // 0(fifo disabled), 1, 2, 3, 4 : 25, 50, 75, 100%
345 
349  bool periph_inc_size_4; // PINCOS bit
350 
354  bool transfert_end_ctrl_by_periph; // PFCTRL bit
355 #endif
356 #ifdef STM32_DMA_DRIVER_USER_DATA_FIELD
357  void *user_data;
358 #endif
359 } DMAConfig;
360 
361 
365 struct DMADriver {
369  const stm32_dma_stream_t *dmastream;
370 
375 
376 #if STM32_DMA_USE_WAIT || defined(__DOXYGEN__)
377 
380  thread_reference_t thread;
381 #endif
382 #if STM32_DMA_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
383 
386  mutex_t mutex;
387 #endif /* STM32_DMA_USE_MUTUAL_EXCLUSION */
388 #if STM32_DMA_USE_ASYNC_TIMOUT
389 
392  uint8_t *volatile currPtr;
393 
397  virtual_timer_t vt;
398 #endif
399 
404  void *mem0p;
405 
410 
411 #if __DCACHE_PRESENT
412 
415  volatile void * periphp;
416 #endif
417 
418 #if STM32_DMA_ADVANCED
419 
422  uint32_t fifomode;
423 #endif
424 
428  size_t size;
429 
430 #if CH_DBG_SYSTEM_STATE_CHECK
431  volatile size_t nbTransferError;
432  volatile size_t nbDirectModeError;
433  volatile size_t nbFifoError;
434  volatile size_t nbFifoFull;
435  volatile size_t nbFifoEmpty;
436  volatile dmaerrormask_t lastError;
437 #endif
438 
441  volatile dmastate_t state;
442 
443 
448 };
449 
450 
451 
452 void dmaObjectInit(DMADriver *dmap);
453 bool dmaStart(DMADriver *dmap, const DMAConfig *cfg);
454 void dmaStop(DMADriver *dmap);
455 
456 #if STM32_DMA_USE_WAIT == TRUE
457 msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size,
458  sysinterval_t timeout);
459 // helper
460 static inline msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size)
461 {
462  return dmaTransfertTimeout(dmap, periphp, mem0p, size, TIME_INFINITE);
463 }
464 #endif
465 #if STM32_DMA_USE_MUTUAL_EXCLUSION == TRUE
466 void dmaAcquireBus(DMADriver *dmap);
467 void dmaReleaseBus(DMADriver *dmap);
468 #endif
469 bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void * mem0p, const size_t size);
470 void dmaStopTransfert(DMADriver *dmap);
471 
472 bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
473 void dmaStopTransfertI(DMADriver *dmap);
474 
475 static inline dmastate_t dmaGetState(DMADriver *dmap) {return dmap->state;}
476 
477 // low level driver
478 
479 bool dma_lld_start(DMADriver *dmap);
480 void dma_lld_stop(DMADriver *dmap);
481 
482 
483 bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size);
484 
485 
487 
488 #if STM32_DMA_USE_ASYNC_TIMOUT
489 void dma_lld_serve_timeout_interrupt(void *arg);
490 #endif
491 
492 #if STM32_DMA_USE_ASYNC_TIMOUT
493 typedef enum {FROM_TIMOUT_CODE, FROM_HALF_CODE, FROM_FULL_CODE, FROM_NON_CIRCULAR_CODE} CbCallContext;
494 static inline void async_timout_enabled_call_end_cb(DMADriver *dmap, const CbCallContext context)
495 {
496  uint8_t *const baseAddr = dmap->currPtr;
497  const size_t fullSize = dmap->size;
498  const size_t halfSize = fullSize / 2;
499  size_t rem = 0;
500  uint8_t *const basePtr = (uint8_t *) dmap->mem0p;
501  uint8_t *const midPtr = ((uint8_t *) dmap->mem0p) + (dmap->config->msize * halfSize);
502  uint8_t *const endPtr = ((uint8_t *) dmap->mem0p) + (dmap->config->msize * fullSize);
503 
504 
505  switch (context) {
506  case (FROM_HALF_CODE) :
507  if (midPtr > baseAddr) {
508  rem = (midPtr - baseAddr) / dmap->config->msize;
509  dmap->currPtr = midPtr;
510  }
511  break;
512 
513  case (FROM_FULL_CODE) :
514  case (FROM_NON_CIRCULAR_CODE) :
515  rem = (endPtr - baseAddr) / dmap->config->msize;
516  dmap->currPtr = basePtr;
517  break;
518 
519  case (FROM_TIMOUT_CODE) : {
520  const size_t dmaCNT = dmaStreamGetTransactionSize(dmap->dmastream);
521  const size_t index = (baseAddr - basePtr) / dmap->config->msize;
522 
523  // if following test fail, it's because DMACNT has rollover during the ISR,
524  // so that we can safely ignore this TIMOUT event since a fullcode ISR will follow
525  // briefly
526  if (fullSize >= (dmaCNT + index)) {
527  rem = (fullSize - dmaCNT - index);
528  dmap->currPtr = baseAddr + (rem * dmap->config->msize);
529  }
530  }
531  break;
532  }
533 
534  if (dmap->config->end_cb != NULL && (rem > 0)) {
535  dmap->config->end_cb(dmap, baseAddr, rem);
536  }
537 }
538 #endif
539 
540 static inline void _dma_isr_half_code(DMADriver *dmap)
541 {
542 #if STM32_DMA_USE_ASYNC_TIMOUT
543  if (dmap->config->timeout != TIME_INFINITE) {
544  chSysLockFromISR();
545  chVTSetI(&dmap->vt, dmap->config->timeout,
546  &dma_lld_serve_timeout_interrupt, (void *) dmap);
547  chSysUnlockFromISR();
548  }
549  async_timout_enabled_call_end_cb(dmap, FROM_HALF_CODE);
550 #else
551  if (dmap->config->end_cb != NULL) {
552  dmap->config->end_cb(dmap, dmap->mem0p, dmap->size / 2);
553  }
554 #endif
555 }
556 
557 static inline void _dma_isr_full_code(DMADriver *dmap)
558 {
559  if (dmap->config->circular) {
560 #if STM32_DMA_USE_ASYNC_TIMOUT
561  if (dmap->config->timeout != TIME_INFINITE) {
562  chSysLockFromISR();
563  chVTSetI(&dmap->vt, dmap->config->timeout,
564  &dma_lld_serve_timeout_interrupt, (void *) dmap);
565  chSysUnlockFromISR();
566  }
567  async_timout_enabled_call_end_cb(dmap, FROM_FULL_CODE);
568 #else
569  /* Callback handling.*/
570  if (dmap->config->end_cb != NULL) {
571  if (dmap->size > 1) {
572  /* Invokes the callback passing the 2nd half of the buffer.*/
573  const size_t half_index = dmap->size / 2;
574  const uint8_t *byte_array_p = ((uint8_t *) dmap->mem0p) +
575  dmap->config->msize * half_index;
576  dmap->config->end_cb(dmap, (void *) byte_array_p, half_index);
577  } else {
578  /* Invokes the callback passing the whole buffer.*/
579  dmap->config->end_cb(dmap, dmap->mem0p, dmap->size);
580  }
581  }
582 #endif
583  } else { // not circular
584  /* End transfert.*/
585 #if STM32_DMA_USE_ASYNC_TIMOUT
586  if (dmap->config->timeout != TIME_INFINITE) {
587  chSysLockFromISR();
588  chVTResetI(&dmap->vt);
589  chSysUnlockFromISR();
590  }
591 #endif
593  if (dmap->config->end_cb != NULL) {
594  dmap->state = DMA_COMPLETE;
595  /* Invoke the callback passing the whole buffer.*/
596 #if STM32_DMA_USE_ASYNC_TIMOUT
597  async_timout_enabled_call_end_cb(dmap, FROM_NON_CIRCULAR_CODE);
598 #else
599  dmap->config->end_cb(dmap, dmap->mem0p, dmap->size);
600 #endif
601  if (dmap->state == DMA_COMPLETE) {
602  dmap->state = DMA_READY;
603  }
604  } else {
605  dmap->state = DMA_READY;
606  }
607  _dma_wakeup_isr(dmap);
608  }
609 }
610 
611 static inline void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err) {
612 #if CH_DBG_SYSTEM_STATE_CHECK == TRUE
613  if (err & DMA_ERR_TRANSFER_ERROR)
614  dmap->nbTransferError++;
615  if (err & DMA_ERR_DIRECTMODE_ERROR)
616  dmap->nbDirectModeError++;
617  if (err & DMA_ERR_FIFO_ERROR) {
618  dmap->nbFifoError++;
619  if (err & DMA_ERR_FIFO_FULL)
620  dmap->nbFifoFull++;
621  if (err & DMA_ERR_FIFO_EMPTY)
622  dmap->nbFifoEmpty++;
623  }
624  dmap->lastError = err;
625 #endif
628  else
629  return;
630 
631  if (dmap->config->error_cb != NULL) {
632  dmap->state = DMA_ERROR;
633  dmap->config->error_cb(dmap, err);
634  if (dmap->state == DMA_ERROR)
635  dmap->state = DMA_READY;
636  } else {
637  dmap->state = DMA_READY;
638  }
639  _dma_timeout_isr(dmap);
640 }
641 
642 
643 #ifdef __cplusplus
644 }
645 #endif
DMAConfig::circular
bool circular
Enables the circular buffer mode for the stream.
Definition: hal_stm32_dma.h:276
DMA_DIR_M2P
@ DMA_DIR_M2P
MEMORY to PERIPHERAL
Definition: hal_stm32_dma.h:89
DMA_ACTIVE
@ DMA_ACTIVE
Transfering.
Definition: hal_stm32_dma.h:66
DMA_READY
@ DMA_READY
Ready.
Definition: hal_stm32_dma.h:65
DMADriver::size
size_t size
hold size of current transaction
Definition: hal_stm32_dma.h:428
dmacallback_t
void(* dmacallback_t)(DMADriver *dmap, void *buffer, const size_t n)
DMA notification callback type.
Definition: hal_stm32_dma.h:106
channel
static uint8_t channel
Definition: ADS8344.c:80
dmaTransfert
static msg_t dmaTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Definition: hal_stm32_dma.h:460
DMADriver::dmastream
const stm32_dma_stream_t * dmastream
DMA stream associated with peripheral or memory.
Definition: hal_stm32_dma.h:369
DMAConfig::dma_priority
uint8_t dma_priority
DMA priority (1 .
Definition: hal_stm32_dma.h:306
DMAConfig::irq_priority
uint8_t irq_priority
DMA IRQ priority (2 .
Definition: hal_stm32_dma.h:311
dmaStartTransfertI
bool dmaStartTransfertI(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
Definition: hal_stm32_dma.c:174
dma_lld_start
bool dma_lld_start(DMADriver *dmap)
Configures and activates the DMA peripheral.
Definition: hal_stm32_dma.c:409
dmaTransfertTimeout
msg_t dmaTransfertTimeout(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size, sysinterval_t timeout)
Performs a DMA transaction.
Definition: hal_stm32_dma.c:328
dmadirection_t
dmadirection_t
DMA transfert direction.
Definition: hal_stm32_dma.h:87
DMAConfig::inc_peripheral_addr
bool inc_peripheral_addr
Enable increment of peripheral address after each transfert.
Definition: hal_stm32_dma.h:264
mutex
static pthread_mutex_t mutex
Definition: cv_detect_color_object.c:46
_dma_timeout_isr
#define _dma_timeout_isr(dmap)
Wakes up the waiting thread with a timeout message.
Definition: hal_stm32_dma.h:169
_dma_isr_full_code
static void _dma_isr_full_code(DMADriver *dmap)
Common ISR code, full buffer event.
Definition: hal_stm32_dma.h:557
uint32_t
unsigned long uint32_t
Definition: types.h:18
DMAConfig::msize
uint8_t msize
DMA memory data granurality in bytes (1,2,4)
Definition: hal_stm32_dma.h:321
DMA_ERR_FIFO_FULL
@ DMA_ERR_FIFO_FULL
DMA FIFO overrun.
Definition: hal_stm32_dma.h:80
dmaStop
void dmaStop(DMADriver *dmap)
Deactivates the DMA peripheral.
Definition: hal_stm32_dma.c:114
timeout
static float timeout
Definition: object_tracking.c:70
DMADriver::mem0p
void * mem0p
memory address
Definition: hal_stm32_dma.h:404
dmaerrormask_t
dmaerrormask_t
Possible DMA failure causes.
Definition: hal_stm32_dma.h:76
DMA_ERR_FIFO_EMPTY
@ DMA_ERR_FIFO_EMPTY
DMA FIFO underrun.
Definition: hal_stm32_dma.h:81
dmaStopTransfert
void dmaStopTransfert(DMADriver *dmap)
Stops an ongoing transaction.
Definition: hal_stm32_dma.c:257
DMAConfig::end_cb
dmacallback_t end_cb
Callback function associated to the stream or NULL.
Definition: hal_stm32_dma.h:282
dmaerrorcallback_t
void(* dmaerrorcallback_t)(DMADriver *dmap, dmaerrormask_t err)
DMA error callback type.
Definition: hal_stm32_dma.h:116
dmaStopTransfertI
void dmaStopTransfertI(DMADriver *dmap)
Stops an ongoing transaction.
Definition: hal_stm32_dma.c:285
DMA_DIR_P2M
@ DMA_DIR_P2M
PERIPHERAL to MEMORY
Definition: hal_stm32_dma.h:88
dma_lld_start_transfert
bool dma_lld_start_transfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
Definition: hal_stm32_dma.c:691
dmaAcquireBus
void dmaAcquireBus(DMADriver *dmap)
Gains exclusive access to the DMA peripheral.
Definition: hal_stm32_dma.c:358
_dma_isr_error_code
static void _dma_isr_error_code(DMADriver *dmap, dmaerrormask_t err)
Common ISR code, error event.
Definition: hal_stm32_dma.h:611
uint8_t
unsigned char uint8_t
Definition: types.h:14
DMA_DIR_M2M
@ DMA_DIR_M2M
MEMORY to MEMORY
Definition: hal_stm32_dma.h:90
DMA_COMPLETE
@ DMA_COMPLETE
Transfert complete.
Definition: hal_stm32_dma.h:67
DMA_ERR_FIFO_ERROR
@ DMA_ERR_FIFO_ERROR
DMA FIFO error.
Definition: hal_stm32_dma.h:79
DMA_ERR_DIRECTMODE_ERROR
@ DMA_ERR_DIRECTMODE_ERROR
DMA Direct Mode failure.
Definition: hal_stm32_dma.h:78
DMADriver::state
volatile dmastate_t state
Driver state.
Definition: hal_stm32_dma.h:441
if
if(GpsFixValid() &&e_identification_started)
Definition: e_identification_fr.c:159
dmastate_t
dmastate_t
Driver state machine possible states.
Definition: hal_stm32_dma.h:62
dma_lld_stop
void dma_lld_stop(DMADriver *dmap)
Deactivates the DMA peripheral.
Definition: hal_stm32_dma.c:735
DMAConfig::inc_memory_addr
bool inc_memory_addr
Enable increment of memory address after each transfert.
Definition: hal_stm32_dma.h:270
DMAConfig::direction
dmadirection_t direction
DMA transaction direction.
Definition: hal_stm32_dma.h:300
DMA_UNINIT
@ DMA_UNINIT
Not initialized.
Definition: hal_stm32_dma.h:63
DMADriver
Structure representing a DMA driver.
Definition: hal_stm32_dma.h:365
DMAConfig::psize
uint8_t psize
DMA peripheral data granurality in bytes (1,2,4)
Definition: hal_stm32_dma.h:316
DMADriver::dmamode
uint32_t dmamode
hold DMA CR register for the stream
Definition: hal_stm32_dma.h:409
DMA_STOP
@ DMA_STOP
Stopped.
Definition: hal_stm32_dma.h:64
DMAConfig::stream
uint32_t stream
stream associated with transaction
Definition: hal_stm32_dma.h:246
DMA_ERROR
@ DMA_ERROR
Transfert error.
Definition: hal_stm32_dma.h:68
DMAConfig
DMA stream configuration structure.
Definition: hal_stm32_dma.h:241
DMADriver::controller
uint8_t controller
controller associated with stream
Definition: hal_stm32_dma.h:447
dmaStart
bool dmaStart(DMADriver *dmap, const DMAConfig *cfg)
Configures and activates the DMA peripheral.
Definition: hal_stm32_dma.c:92
dmaObjectInit
void dmaObjectInit(DMADriver *dmap)
Definition: hal_stm32_dma.c:56
dmaReleaseBus
void dmaReleaseBus(DMADriver *dmap)
Releases exclusive access to the DMA peripheral.
Definition: hal_stm32_dma.c:375
DMAConfig::error_cb
dmaerrorcallback_t error_cb
Error callback or NULL.
Definition: hal_stm32_dma.h:287
dmaGetState
static dmastate_t dmaGetState(DMADriver *dmap)
Definition: hal_stm32_dma.h:475
DMADriver::config
const DMAConfig * config
Current configuration data.
Definition: hal_stm32_dma.h:374
_dma_wakeup_isr
#define _dma_wakeup_isr(dmap)
Wakes up the waiting thread.
Definition: hal_stm32_dma.h:156
dmaStartTransfert
bool dmaStartTransfert(DMADriver *dmap, volatile void *periphp, void *mem0p, const size_t size)
Starts a DMA transaction.
Definition: hal_stm32_dma.c:149
_dma_isr_half_code
static void _dma_isr_half_code(DMADriver *dmap)
Common ISR code, half buffer event.
Definition: hal_stm32_dma.h:540
DMA_ERR_TRANSFER_ERROR
@ DMA_ERR_TRANSFER_ERROR
DMA transfer failure.
Definition: hal_stm32_dma.h:77
dma_lld_stop_transfert
void dma_lld_stop_transfert(DMADriver *dmap)
Stops an ongoing transaction.
Definition: hal_stm32_dma.c:723